From 7e19330e3075d79dbce5d8c126377d64c5301f85 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 19 May 2015 11:37:26 +0200 Subject: score: Fix assert --- cpukit/score/src/threaddispatchdisablelevel.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cpukit/score/src/threaddispatchdisablelevel.c b/cpukit/score/src/threaddispatchdisablelevel.c index f78eb52016..9170f2eb09 100644 --- a/cpukit/score/src/threaddispatchdisablelevel.c +++ b/cpukit/score/src/threaddispatchdisablelevel.c @@ -113,8 +113,10 @@ uint32_t _Thread_Dispatch_decrement_disable_level( void ) _Giant_Do_release( cpu_self ); _Assert( - ( disable_level == 0 && _Giant.owner_cpu != cpu_self ) - || ( disable_level != 0 && _Giant.owner_cpu == cpu_self ) + ( disable_level == cpu_self->isr_nest_level + && _Giant.owner_cpu != cpu_self ) + || ( disable_level > cpu_self->isr_nest_level + && _Giant.owner_cpu == cpu_self ) ); _Profiling_Thread_dispatch_enable( cpu_self, disable_level ); -- cgit v1.2.3 From cf255ff0b2e422a8b6b659240efd0856411f8580 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 24 Apr 2015 11:47:35 +0200 Subject: score: Add _SMP_Assert() --- cpukit/score/include/rtems/score/assert.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cpukit/score/include/rtems/score/assert.h b/cpukit/score/include/rtems/score/assert.h index 43ec2d0e38..63083784fa 100644 --- a/cpukit/score/include/rtems/score/assert.h +++ b/cpukit/score/include/rtems/score/assert.h @@ -82,6 +82,15 @@ extern "C" { #define _Assert( _e ) ( ( void ) 0 ) #endif +/** + * @brief Like _Assert(), but only armed if RTEMS_SMP is defined. + */ +#if defined( RTEMS_SMP ) + #define _SMP_Assert( _e ) _Assert( _e ) +#else + #define _SMP_Assert( _e ) ( ( void ) 0 ) +#endif + /** * @brief Returns true if thread dispatching is allowed. * -- cgit v1.2.3 From 22788bc2baeb8e13bb0d6b6d05782a6ccfd4cb67 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 23 Apr 2015 13:01:05 +0200 Subject: score: _Thread_queue_Extract() Remove thread queue parameter from _Thread_queue_Extract() since the current thread queue is stored in the thread control block. --- cpukit/rtems/src/msgmp.c | 2 +- cpukit/rtems/src/partmp.c | 2 +- cpukit/rtems/src/regionmp.c | 2 +- cpukit/rtems/src/regionprocessqueue.c | 2 +- cpukit/rtems/src/semmp.c | 2 +- cpukit/score/include/rtems/score/threadqimpl.h | 16 +++++--------- cpukit/score/src/corerwlockrelease.c | 2 +- cpukit/score/src/mpci.c | 2 +- cpukit/score/src/threadqenqueue.c | 14 ++++++------- cpukit/score/src/threadqextractwithproxy.c | 7 +------ cpukit/score/src/threadqprocesstimeout.c | 1 - testsuites/sptests/spthreadq01/init.c | 29 ++++---------------------- 12 files changed, 23 insertions(+), 58 deletions(-) diff --git a/cpukit/rtems/src/msgmp.c b/cpukit/rtems/src/msgmp.c index 7043138963..ddad64a17a 100644 --- a/cpukit/rtems/src/msgmp.c +++ b/cpukit/rtems/src/msgmp.c @@ -291,7 +291,7 @@ void _Message_queue_MP_Process_packet ( the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); if (! _Thread_Is_null( the_thread ) ) - _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + _Thread_queue_Extract( the_thread ); _MPCI_Return_packet( the_packet_prefix ); break; diff --git a/cpukit/rtems/src/partmp.c b/cpukit/rtems/src/partmp.c index 943c24ac6d..f41fd227e9 100644 --- a/cpukit/rtems/src/partmp.c +++ b/cpukit/rtems/src/partmp.c @@ -209,7 +209,7 @@ void _Partition_MP_Process_packet ( the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); if ( ! _Thread_Is_null( the_thread ) ) - _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + _Thread_queue_Extract( the_thread ); _MPCI_Return_packet( the_packet_prefix ); break; diff --git a/cpukit/rtems/src/regionmp.c b/cpukit/rtems/src/regionmp.c index 58dfa99dde..8bce822193 100644 --- a/cpukit/rtems/src/regionmp.c +++ b/cpukit/rtems/src/regionmp.c @@ -195,7 +195,7 @@ void _Region_MP_Process_packet ( the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); if ( ! _Thread_Is_null( the_thread ) ) - _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + _Thread_queue_Extract( the_thread ); _MPCI_Return_packet( the_packet_prefix ); break; diff --git a/cpukit/rtems/src/regionprocessqueue.c b/cpukit/rtems/src/regionprocessqueue.c index 54081af84d..a06a077e3d 100644 --- a/cpukit/rtems/src/regionprocessqueue.c +++ b/cpukit/rtems/src/regionprocessqueue.c @@ -61,7 +61,7 @@ void _Region_Process_queue( *(void **)the_thread->Wait.return_argument = the_segment; the_region->number_of_used_blocks += 1; - _Thread_queue_Extract( &the_region->Wait_queue, the_thread ); + _Thread_queue_Extract( the_thread ); the_thread->Wait.return_code = RTEMS_SUCCESSFUL; } _Thread_Enable_dispatch(); diff --git a/cpukit/rtems/src/semmp.c b/cpukit/rtems/src/semmp.c index eabd1b7a0b..d94d90870a 100644 --- a/cpukit/rtems/src/semmp.c +++ b/cpukit/rtems/src/semmp.c @@ -188,7 +188,7 @@ void _Semaphore_MP_Process_packet ( the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); if ( ! _Thread_Is_null( the_thread ) ) - _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + _Thread_queue_Extract( the_thread ); _MPCI_Return_packet( the_packet_prefix ); break; diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 6eac3643f4..6fc38cfa5b 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -78,25 +78,20 @@ void _Thread_queue_Enqueue( /** * @brief Extracts thread from thread queue. * - * This routine removes @a the_thread from @a the_thread_queue + * This routine removes @a the_thread its thread queue * and cancels any timeouts associated with this blocking. * - * @param[in] the_thread_queue is the pointer to the ThreadQ header * @param[in] the_thread is the pointer to a thread control block that * is to be removed */ -void _Thread_queue_Extract( - Thread_queue_Control *the_thread_queue, - Thread_Control *the_thread -); +void _Thread_queue_Extract( Thread_Control *the_thread ); /** * @brief Extracts thread from thread queue (w/return code). * - * This routine removes @a the_thread from @a the_thread_queue + * This routine removes @a the_thread its thread queue * and cancels any timeouts associated with this blocking. * - * @param[in] the_thread_queue is the pointer to the ThreadQ header * @param[in] the_thread is the pointer to a thread control block that * is to be removed * @param[in] return_code specifies the status to be returned. @@ -105,9 +100,8 @@ void _Thread_queue_Extract( * + single case */ void _Thread_queue_Extract_with_return_code( - Thread_queue_Control *the_thread_queue, - Thread_Control *the_thread, - uint32_t return_code + Thread_Control *the_thread, + uint32_t return_code ); /** diff --git a/cpukit/score/src/corerwlockrelease.c b/cpukit/score/src/corerwlockrelease.c index efaf67d351..bd39213c87 100644 --- a/cpukit/score/src/corerwlockrelease.c +++ b/cpukit/score/src/corerwlockrelease.c @@ -87,7 +87,7 @@ CORE_RWLock_Status _CORE_RWLock_Release( next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ) return CORE_RWLOCK_SUCCESSFUL; the_rwlock->number_of_readers += 1; - _Thread_queue_Extract( &the_rwlock->Wait_queue, next ); + _Thread_queue_Extract( next ); } } diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 9b623b253f..424bcb4d33 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -262,7 +262,7 @@ Thread_Control *_MPCI_Process_response ( the_thread = NULL; /* IMPOSSIBLE */ break; case OBJECTS_LOCAL: - _Thread_queue_Extract( &_MPCI_Remote_blocked_threads, the_thread ); + _Thread_queue_Extract( the_thread ); the_thread->Wait.return_code = the_packet->return_code; _Objects_Put_without_thread_dispatch( &the_thread->Object ); break; diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 5c237560f4..0e16f59c46 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -185,11 +185,11 @@ void _Thread_queue_Enqueue( } void _Thread_queue_Extract_with_return_code( - Thread_queue_Control *the_thread_queue, - Thread_Control *the_thread, - uint32_t return_code + Thread_Control *the_thread, + uint32_t return_code ) { + Thread_queue_Control *the_thread_queue; ISR_lock_Context lock_context; _Thread_queue_Acquire( &lock_context ); @@ -199,6 +199,8 @@ void _Thread_queue_Extract_with_return_code( return; } + the_thread_queue = the_thread->Wait.queue; + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { _Chain_Extract_unprotected( &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ @@ -220,13 +222,9 @@ void _Thread_queue_Extract_with_return_code( _Thread_blocking_operation_Finalize( the_thread, &lock_context ); } -void _Thread_queue_Extract( - Thread_queue_Control *the_thread_queue, - Thread_Control *the_thread -) +void _Thread_queue_Extract( Thread_Control *the_thread ) { _Thread_queue_Extract_with_return_code( - the_thread_queue, the_thread, the_thread->Wait.return_code ); diff --git a/cpukit/score/src/threadqextractwithproxy.c b/cpukit/score/src/threadqextractwithproxy.c index fb06526e9e..72043a094d 100644 --- a/cpukit/score/src/threadqextractwithproxy.c +++ b/cpukit/score/src/threadqextractwithproxy.c @@ -31,8 +31,6 @@ void _Thread_queue_Extract_with_proxy( Thread_Control *the_thread ) { - Thread_queue_Control *the_thread_queue; - #if defined(RTEMS_MULTIPROCESSING) States_Control state; @@ -50,8 +48,5 @@ void _Thread_queue_Extract_with_proxy( } #endif - the_thread_queue = the_thread->Wait.queue; - if ( the_thread_queue != NULL ) { - _Thread_queue_Extract( the_thread_queue, the_thread ); - } + _Thread_queue_Extract( the_thread ); } diff --git a/cpukit/score/src/threadqprocesstimeout.c b/cpukit/score/src/threadqprocesstimeout.c index 616901900d..dbb8f5ce45 100644 --- a/cpukit/score/src/threadqprocesstimeout.c +++ b/cpukit/score/src/threadqprocesstimeout.c @@ -69,7 +69,6 @@ void _Thread_queue_Process_timeout( * queue initialization. */ _Thread_queue_Extract_with_return_code( - the_thread_queue, the_thread, the_thread_queue->timeout_status ); diff --git a/testsuites/sptests/spthreadq01/init.c b/testsuites/sptests/spthreadq01/init.c index 240cd1a9e8..5add92bb5d 100644 --- a/testsuites/sptests/spthreadq01/init.c +++ b/testsuites/sptests/spthreadq01/init.c @@ -18,38 +18,17 @@ const char rtems_test_name[] = "SPTHREADQ 1"; -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); -void threadq_first_empty( - const char *discipline_string, - Thread_queue_Disciplines discipline -); - -void threadq_first_empty( - const char *discipline_string, - Thread_queue_Disciplines discipline +static rtems_task Init( + rtems_task_argument ignored ) { - Thread_queue_Control tq; - - printf( "Init - initialize thread queue for %s\n", discipline_string ); - _Thread_queue_Initialize( &tq, discipline, 3 ); + TEST_BEGIN(); puts( "Init - _Thread_queue_Extract - thread not blocked on a thread queue" ); _Thread_Disable_dispatch(); - _Thread_queue_Extract( &tq, _Thread_Executing ); + _Thread_queue_Extract( _Thread_Executing ); _Thread_Enable_dispatch(); /* is there more to check? */ -} - -rtems_task Init( - rtems_task_argument ignored -) -{ - TEST_BEGIN(); - - threadq_first_empty( "FIFO", THREAD_QUEUE_DISCIPLINE_FIFO ); - threadq_first_empty( "Priority", THREAD_QUEUE_DISCIPLINE_PRIORITY ); TEST_END(); rtems_test_exit(0); -- cgit v1.2.3 From 56729d83c99ee393c707acfcbcd7d290f97fd07d Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 23 Apr 2015 21:29:56 +0200 Subject: score: Delete STATES_WAITING_ON_THREAD_QUEUE Avoid the usage of the current thread state in _Thread_queue_Extract_with_return_code() since thread queues should not know anything about thread states. --- cpukit/posix/src/psignalunblockthread.c | 6 +++--- cpukit/score/include/rtems/score/statesimpl.h | 26 ++------------------------ cpukit/score/src/threadqenqueue.c | 5 ++--- 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/cpukit/posix/src/psignalunblockthread.c b/cpukit/posix/src/psignalunblockthread.c index c56c1502a1..1b3db68262 100644 --- a/cpukit/posix/src/psignalunblockthread.c +++ b/cpukit/posix/src/psignalunblockthread.c @@ -114,11 +114,11 @@ bool _POSIX_signals_Unblock_thread( * In pthread_cond_wait, a thread will be blocking on a thread * queue, but is also interruptible by a POSIX signal. */ - if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) ) - _Thread_queue_Extract_with_proxy( the_thread ); - else if ( _States_Is_delaying(the_thread->current_state) ) { + if ( _States_Is_delaying(the_thread->current_state) ) { (void) _Watchdog_Remove( &the_thread->Timer ); _Thread_Unblock( the_thread ); + } else { + _Thread_queue_Extract_with_proxy( the_thread ); } } } diff --git a/cpukit/score/include/rtems/score/statesimpl.h b/cpukit/score/include/rtems/score/statesimpl.h index 9f94675c89..d1c402e643 100644 --- a/cpukit/score/include/rtems/score/statesimpl.h +++ b/cpukit/score/include/rtems/score/statesimpl.h @@ -105,19 +105,14 @@ extern "C" { STATES_WAITING_FOR_BSD_WAKEUP | \ STATES_WAITING_FOR_RWLOCK ) -/** This macro corresponds to a task waiting which is blocked on - * a thread queue. */ -#define STATES_WAITING_ON_THREAD_QUEUE \ - ( STATES_LOCALLY_BLOCKED | \ - STATES_WAITING_FOR_RPC_REPLY ) - /** This macro corresponds to a task waiting which is blocked. */ #define STATES_BLOCKED ( STATES_DELAYING | \ + STATES_LOCALLY_BLOCKED | \ STATES_WAITING_FOR_TIME | \ STATES_WAITING_FOR_PERIOD | \ STATES_WAITING_FOR_EVENT | \ + STATES_WAITING_FOR_RPC_REPLY | \ STATES_WAITING_FOR_SYSTEM_EVENT | \ - STATES_WAITING_ON_THREAD_QUEUE | \ STATES_INTERRUPTIBLE_BY_SIGNAL ) /** All state bits set to one (provided for _Thread_Ready()) */ @@ -414,23 +409,6 @@ RTEMS_INLINE_ROUTINE bool _States_Is_locally_blocked ( return (the_states & STATES_LOCALLY_BLOCKED); } -/** - * This function returns true if one of the states which indicates - * that a task is blocked waiting for a local resource is set in - * the_states, and false otherwise. - * - * @param[in] the_states is the task state set to test - * - * @return This method returns true if the state indicates that the - * assocated thread is waiting on a thread queue. - */ -RTEMS_INLINE_ROUTINE bool _States_Is_waiting_on_thread_queue ( - States_Control the_states -) -{ - return (the_states & STATES_WAITING_ON_THREAD_QUEUE); -} - /** * This function returns true if one of the states which indicates * that a task is blocked is set in the_states, and false otherwise. diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 0e16f59c46..5f94ec99c9 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -194,13 +194,12 @@ void _Thread_queue_Extract_with_return_code( _Thread_queue_Acquire( &lock_context ); - if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) { + the_thread_queue = the_thread->Wait.queue; + if ( the_thread_queue == NULL ) { _Thread_queue_Release( &lock_context ); return; } - the_thread_queue = the_thread->Wait.queue; - if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { _Chain_Extract_unprotected( &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ -- cgit v1.2.3 From a61d38501ac25f81913f2766a64e43f8dfdba2b0 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 24 Apr 2015 10:51:24 +0200 Subject: score: Optimize _Thread_queue_Compare_priority() --- cpukit/score/src/threadq.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c index bdd380d188..0ea0c82d83 100644 --- a/cpukit/score/src/threadq.c +++ b/cpukit/score/src/threadq.c @@ -29,19 +29,20 @@ RBTree_Compare_result _Thread_queue_Compare_priority( const RBTree_Node *right ) { - Priority_Control left_priority = - THREAD_RBTREE_NODE_TO_THREAD( left )->current_priority; - Priority_Control right_priority = - THREAD_RBTREE_NODE_TO_THREAD( right )->current_priority; + const Thread_Control *left_thread; + const Thread_Control *right_thread; + Priority_Control left_prio; + Priority_Control right_prio; + + left_thread = THREAD_RBTREE_NODE_TO_THREAD( left ); + right_thread = THREAD_RBTREE_NODE_TO_THREAD( right ); + left_prio = left_thread->current_priority; + right_prio = right_thread->current_priority; /* * SuperCore priorities use lower numbers to indicate greater importance. */ - if ( left_priority == right_priority ) - return 0; - if ( left_priority < right_priority ) - return -1; - return 1; + return ( left_prio > right_prio ) - ( left_prio < right_prio ); } void _Thread_queue_Initialize( -- cgit v1.2.3 From 290309014c15b4eceee9f77c90eb3c81cc223f4b Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 15 Apr 2015 11:26:46 +0200 Subject: score: Add header to _Watchdog_Remove() Add watchdog header parameter to _Watchdog_Remove() to be in line with the other operations. Add _Watchdog_Remove_ticks() and _Watchdog_Remove_seconds() for convenience. Update #2307. --- cpukit/posix/src/alarm.c | 2 +- cpukit/posix/src/psignalunblockthread.c | 2 +- cpukit/posix/src/pthread.c | 2 +- cpukit/posix/src/pthreadsetschedparam.c | 4 ++-- cpukit/posix/src/timerdelete.c | 2 +- cpukit/posix/src/timerinserthelper.c | 2 +- cpukit/posix/src/timersettime.c | 2 +- cpukit/posix/src/ualarm.c | 2 +- cpukit/rtems/include/rtems/rtems/timerimpl.h | 13 ++++++++++--- cpukit/rtems/src/eventseize.c | 2 +- cpukit/rtems/src/eventsurrender.c | 2 +- cpukit/rtems/src/ratemoncancel.c | 2 +- cpukit/rtems/src/ratemondelete.c | 2 +- cpukit/rtems/src/timercancel.c | 3 +-- cpukit/rtems/src/timercreate.c | 23 +++++++++++++++++++++++ cpukit/rtems/src/timerdelete.c | 2 +- cpukit/rtems/src/timerfireafter.c | 2 +- cpukit/rtems/src/timerfirewhen.c | 2 +- cpukit/rtems/src/timerreset.c | 2 +- cpukit/rtems/src/timerserver.c | 19 ++++++++++++++++--- cpukit/rtems/src/timerserverfireafter.c | 2 +- cpukit/rtems/src/timerserverfirewhen.c | 2 +- cpukit/score/include/rtems/score/mrspimpl.h | 2 +- cpukit/score/include/rtems/score/watchdogimpl.h | 18 +++++++++++++++++- cpukit/score/src/threadqenqueue.c | 2 +- cpukit/score/src/threadrestart.c | 4 ++-- cpukit/score/src/watchdogremove.c | 1 + cpukit/score/src/watchdogtickle.c | 2 +- testsuites/sptests/spintrcritical08/init.c | 2 +- testsuites/sptests/spintrcritical09/init.c | 2 +- 30 files changed, 94 insertions(+), 35 deletions(-) diff --git a/cpukit/posix/src/alarm.c b/cpukit/posix/src/alarm.c index 48036617d4..6f051d7190 100644 --- a/cpukit/posix/src/alarm.c +++ b/cpukit/posix/src/alarm.c @@ -73,7 +73,7 @@ unsigned int alarm( _Thread_Disable_dispatch(); - state = _Watchdog_Remove( the_timer ); + state = _Watchdog_Remove_seconds( the_timer ); if ( (state == WATCHDOG_ACTIVE) || (state == WATCHDOG_REMOVE_IT) ) { /* * The stop_time and start_time fields are snapshots of ticks since diff --git a/cpukit/posix/src/psignalunblockthread.c b/cpukit/posix/src/psignalunblockthread.c index 1b3db68262..3b310a90b7 100644 --- a/cpukit/posix/src/psignalunblockthread.c +++ b/cpukit/posix/src/psignalunblockthread.c @@ -115,7 +115,7 @@ bool _POSIX_signals_Unblock_thread( * queue, but is also interruptible by a POSIX signal. */ if ( _States_Is_delaying(the_thread->current_state) ) { - (void) _Watchdog_Remove( &the_thread->Timer ); + _Watchdog_Remove_ticks( &the_thread->Timer ); _Thread_Unblock( the_thread ); } else { _Thread_queue_Extract_with_proxy( the_thread ); diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index 4d28de536f..97882bf4cb 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -286,7 +286,7 @@ static void _POSIX_Threads_Terminate_extension( *(void **)the_thread->Wait.return_argument = value_ptr; if ( api->schedpolicy == SCHED_SPORADIC ) - (void) _Watchdog_Remove( &api->Sporadic_timer ); + _Watchdog_Remove_ticks( &api->Sporadic_timer ); _Thread_Enable_dispatch(); } diff --git a/cpukit/posix/src/pthreadsetschedparam.c b/cpukit/posix/src/pthreadsetschedparam.c index d5d0a5ba8a..dcb70bdec8 100644 --- a/cpukit/posix/src/pthreadsetschedparam.c +++ b/cpukit/posix/src/pthreadsetschedparam.c @@ -70,7 +70,7 @@ int pthread_setschedparam( api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( api->schedpolicy == SCHED_SPORADIC ) - (void) _Watchdog_Remove( &api->Sporadic_timer ); + _Watchdog_Remove_ticks( &api->Sporadic_timer ); api->schedpolicy = policy; api->schedparam = *param; @@ -99,7 +99,7 @@ int pthread_setschedparam( case SCHED_SPORADIC: api->ss_high_priority = api->schedparam.sched_priority; - _Watchdog_Remove( &api->Sporadic_timer ); + _Watchdog_Remove_ticks( &api->Sporadic_timer ); _POSIX_Threads_Sporadic_budget_TSR( 0, the_thread ); break; } diff --git a/cpukit/posix/src/timerdelete.c b/cpukit/posix/src/timerdelete.c index 71b25faed9..e090be2aca 100644 --- a/cpukit/posix/src/timerdelete.c +++ b/cpukit/posix/src/timerdelete.c @@ -54,7 +54,7 @@ int timer_delete( case OBJECTS_LOCAL: _Objects_Close( &_POSIX_Timer_Information, &ptimer->Object ); ptimer->state = POSIX_TIMER_STATE_FREE; - (void) _Watchdog_Remove( &ptimer->Timer ); + _Watchdog_Remove_ticks( &ptimer->Timer ); _Objects_Put( &ptimer->Object ); _POSIX_Timer_Free( ptimer ); _Objects_Allocator_unlock(); diff --git a/cpukit/posix/src/timerinserthelper.c b/cpukit/posix/src/timerinserthelper.c index 9d028350ad..4d7c3fb681 100644 --- a/cpukit/posix/src/timerinserthelper.c +++ b/cpukit/posix/src/timerinserthelper.c @@ -39,7 +39,7 @@ bool _POSIX_Timer_Insert_helper( { ISR_Level level; - (void) _Watchdog_Remove( timer ); + _Watchdog_Remove_ticks( timer ); _ISR_Disable( level ); /* diff --git a/cpukit/posix/src/timersettime.c b/cpukit/posix/src/timersettime.c index 6cc378082a..2967df6df0 100644 --- a/cpukit/posix/src/timersettime.c +++ b/cpukit/posix/src/timersettime.c @@ -85,7 +85,7 @@ int timer_settime( /* 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 */ - (void) _Watchdog_Remove( &ptimer->Timer ); + _Watchdog_Remove_ticks( &ptimer->Timer ); /* The old data of the timer are returned */ if ( ovalue ) *ovalue = ptimer->timer_data; diff --git a/cpukit/posix/src/ualarm.c b/cpukit/posix/src/ualarm.c index d9a85e6a92..9235ef165c 100644 --- a/cpukit/posix/src/ualarm.c +++ b/cpukit/posix/src/ualarm.c @@ -72,7 +72,7 @@ useconds_t ualarm( _Thread_Disable_dispatch(); - state = _Watchdog_Remove( the_timer ); + state = _Watchdog_Remove_ticks( the_timer ); if ( (state == WATCHDOG_ACTIVE) || (state == WATCHDOG_REMOVE_IT) ) { /* * The stop_time and start_time fields are snapshots of ticks since diff --git a/cpukit/rtems/include/rtems/rtems/timerimpl.h b/cpukit/rtems/include/rtems/rtems/timerimpl.h index b695d5e2fe..4f200efb75 100644 --- a/cpukit/rtems/include/rtems/rtems/timerimpl.h +++ b/cpukit/rtems/include/rtems/rtems/timerimpl.h @@ -50,9 +50,9 @@ extern "C" { typedef struct Timer_server_Control Timer_server_Control; /** - * @brief Method used to schedule the insertion of task based timers. + * @brief Method used for task based timers. */ -typedef void (*Timer_server_Schedule_operation)( +typedef void (*Timer_server_Method)( Timer_server_Control *timer_server, Timer_Control *timer ); @@ -83,10 +83,15 @@ struct Timer_server_Control { */ Thread_Control *thread; + /** + * @brief The cancel method of the timer server. + */ + Timer_server_Method cancel; + /** * @brief The schedule operation method of the timer server. */ - Timer_server_Schedule_operation schedule_operation; + Timer_server_Method schedule_operation; /** * @brief Interval watchdogs triggered by the timer server. @@ -220,6 +225,8 @@ RTEMS_INLINE_ROUTINE bool _Timer_Is_dormant_class ( return ( the_class == TIMER_DORMANT ); } +void _Timer_Cancel( Timer_Control *the_timer ); + /**@}*/ #ifdef __cplusplus diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index 929665641c..36b1964820 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -101,7 +101,7 @@ void _Event_Seize( wait_class | THREAD_WAIT_STATE_BLOCKED ); if ( !success ) { - _Watchdog_Remove( &executing->Timer ); + _Watchdog_Remove_ticks( &executing->Timer ); _Thread_Unblock( executing ); } diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index ba4e429f1e..e29d203f71 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -111,7 +111,7 @@ void _Event_Surrender( _Thread_Lock_release_default( the_thread, lock_context ); _Giant_Acquire( cpu_self ); - _Watchdog_Remove( &the_thread->Timer ); + _Watchdog_Remove_ticks( &the_thread->Timer ); _Thread_Unblock( the_thread ); _Giant_Release( cpu_self ); diff --git a/cpukit/rtems/src/ratemoncancel.c b/cpukit/rtems/src/ratemoncancel.c index d4a9102955..67b230fbfc 100644 --- a/cpukit/rtems/src/ratemoncancel.c +++ b/cpukit/rtems/src/ratemoncancel.c @@ -38,7 +38,7 @@ rtems_status_code rtems_rate_monotonic_cancel( _Objects_Put( &the_period->Object ); return RTEMS_NOT_OWNER_OF_RESOURCE; } - (void) _Watchdog_Remove( &the_period->Timer ); + _Watchdog_Remove_ticks( &the_period->Timer ); the_period->state = RATE_MONOTONIC_INACTIVE; _Scheduler_Release_job( the_period->owner, 0 ); _Objects_Put( &the_period->Object ); diff --git a/cpukit/rtems/src/ratemondelete.c b/cpukit/rtems/src/ratemondelete.c index 971ad8ef3d..77cf3fe306 100644 --- a/cpukit/rtems/src/ratemondelete.c +++ b/cpukit/rtems/src/ratemondelete.c @@ -37,7 +37,7 @@ 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 ); - (void) _Watchdog_Remove( &the_period->Timer ); + _Watchdog_Remove_ticks( &the_period->Timer ); the_period->state = RATE_MONOTONIC_INACTIVE; _Objects_Put( &the_period->Object ); _Rate_monotonic_Free( the_period ); diff --git a/cpukit/rtems/src/timercancel.c b/cpukit/rtems/src/timercancel.c index a8ce1478da..1e737a25bb 100644 --- a/cpukit/rtems/src/timercancel.c +++ b/cpukit/rtems/src/timercancel.c @@ -45,8 +45,7 @@ rtems_status_code rtems_timer_cancel( switch ( location ) { case OBJECTS_LOCAL: - if ( !_Timer_Is_dormant_class( the_timer->the_class ) ) - (void) _Watchdog_Remove( &the_timer->Ticker ); + _Timer_Cancel( the_timer ); _Objects_Put( &the_timer->Object ); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/timercreate.c b/cpukit/rtems/src/timercreate.c index 0b1c44bdc2..2c6d251b8a 100644 --- a/cpukit/rtems/src/timercreate.c +++ b/cpukit/rtems/src/timercreate.c @@ -21,10 +21,33 @@ #include #include #include +#include #include #include #include +void _Timer_Cancel( Timer_Control *the_timer ) +{ + Timer_server_Control *timer_server; + + switch ( the_timer->the_class ) { + case TIMER_INTERVAL: + _Watchdog_Remove_ticks( &the_timer->Ticker ); + break; + case TIMER_TIME_OF_DAY: + _Watchdog_Remove_seconds( &the_timer->Ticker ); + break; + case TIMER_INTERVAL_ON_TASK: + case TIMER_TIME_OF_DAY_ON_TASK: + timer_server = _Timer_server; + (*timer_server->cancel)( timer_server, the_timer ); + break; + default: + _Assert( the_timer->the_class == TIMER_DORMANT ); + break; + } +} + rtems_status_code rtems_timer_create( rtems_name name, rtems_id *id diff --git a/cpukit/rtems/src/timerdelete.c b/cpukit/rtems/src/timerdelete.c index 19232c8096..0849ec5ba6 100644 --- a/cpukit/rtems/src/timerdelete.c +++ b/cpukit/rtems/src/timerdelete.c @@ -38,7 +38,7 @@ rtems_status_code rtems_timer_delete( case OBJECTS_LOCAL: _Objects_Close( &_Timer_Information, &the_timer->Object ); - (void) _Watchdog_Remove( &the_timer->Ticker ); + _Timer_Cancel( the_timer ); _Objects_Put( &the_timer->Object ); _Timer_Free( the_timer ); _Objects_Allocator_unlock(); diff --git a/cpukit/rtems/src/timerfireafter.c b/cpukit/rtems/src/timerfireafter.c index 07862cde8c..84cf46bc37 100644 --- a/cpukit/rtems/src/timerfireafter.c +++ b/cpukit/rtems/src/timerfireafter.c @@ -46,7 +46,7 @@ rtems_status_code rtems_timer_fire_after( switch ( location ) { case OBJECTS_LOCAL: - (void) _Watchdog_Remove( &the_timer->Ticker ); + _Timer_Cancel( the_timer ); _ISR_Disable( level ); diff --git a/cpukit/rtems/src/timerfirewhen.c b/cpukit/rtems/src/timerfirewhen.c index 6ac7d17433..1acbaf9b8f 100644 --- a/cpukit/rtems/src/timerfirewhen.c +++ b/cpukit/rtems/src/timerfirewhen.c @@ -51,7 +51,7 @@ rtems_status_code rtems_timer_fire_when( switch ( location ) { case OBJECTS_LOCAL: - (void) _Watchdog_Remove( &the_timer->Ticker ); + _Timer_Cancel( the_timer ); the_timer->the_class = TIMER_TIME_OF_DAY; _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); _Watchdog_Insert_seconds( diff --git a/cpukit/rtems/src/timerreset.c b/cpukit/rtems/src/timerreset.c index 49c4925aa3..7ab172ea4f 100644 --- a/cpukit/rtems/src/timerreset.c +++ b/cpukit/rtems/src/timerreset.c @@ -67,7 +67,7 @@ rtems_status_code rtems_timer_reset( return RTEMS_INCORRECT_STATE; } #endif - _Watchdog_Remove( &the_timer->Ticker ); + (*timer_server->cancel)( timer_server, the_timer ); (*timer_server->schedule_operation)( timer_server, the_timer ); } else { /* diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index 25191e43d7..15cbdfd59f 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -38,7 +38,7 @@ static void _Timer_server_Stop_interval_system_watchdog( Timer_server_Control *ts ) { - _Watchdog_Remove( &ts->Interval_watchdogs.System_watchdog ); + _Watchdog_Remove_ticks( &ts->Interval_watchdogs.System_watchdog ); } static void _Timer_server_Reset_interval_system_watchdog( @@ -71,7 +71,7 @@ static void _Timer_server_Stop_tod_system_watchdog( Timer_server_Control *ts ) { - _Watchdog_Remove( &ts->TOD_watchdogs.System_watchdog ); + _Watchdog_Remove_seconds( &ts->TOD_watchdogs.System_watchdog ); } static void _Timer_server_Reset_tod_system_watchdog( @@ -210,6 +210,18 @@ static void _Timer_server_Insert_timer_and_make_snapshot( _Thread_Enable_dispatch(); } +static void _Timer_server_Cancel_method( + Timer_server_Control *ts, + Timer_Control *timer +) +{ + if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { + _Watchdog_Remove( &ts->Interval_watchdogs.Header, &timer->Ticker ); + } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { + _Watchdog_Remove( &ts->TOD_watchdogs.Header, &timer->Ticker ); + } +} + static void _Timer_server_Schedule_operation_method( Timer_server_Control *ts, Timer_Control *timer @@ -563,9 +575,10 @@ rtems_status_code rtems_timer_initiate_server( ); /* - * Initialize the pointer to the timer schedule method so applications that + * Initialize the pointer to the timer server methods so applications that * do not use the Timer Server do not have to pull it in. */ + ts->cancel = _Timer_server_Cancel_method; ts->schedule_operation = _Timer_server_Schedule_operation_method; ts->Interval_watchdogs.last_snapshot = _Watchdog_Ticks_since_boot; diff --git a/cpukit/rtems/src/timerserverfireafter.c b/cpukit/rtems/src/timerserverfireafter.c index 125664510f..0636782ae0 100644 --- a/cpukit/rtems/src/timerserverfireafter.c +++ b/cpukit/rtems/src/timerserverfireafter.c @@ -50,7 +50,7 @@ rtems_status_code rtems_timer_server_fire_after( switch ( location ) { case OBJECTS_LOCAL: - (void) _Watchdog_Remove( &the_timer->Ticker ); + _Timer_Cancel( the_timer ); _ISR_Disable( level ); diff --git a/cpukit/rtems/src/timerserverfirewhen.c b/cpukit/rtems/src/timerserverfirewhen.c index 32695fb0e6..0069af1c3b 100644 --- a/cpukit/rtems/src/timerserverfirewhen.c +++ b/cpukit/rtems/src/timerserverfirewhen.c @@ -72,7 +72,7 @@ rtems_status_code rtems_timer_server_fire_when( switch ( location ) { case OBJECTS_LOCAL: - (void) _Watchdog_Remove( &the_timer->Ticker ); + _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(); diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h index c40f41f716..07f78ce7e9 100644 --- a/cpukit/score/include/rtems/score/mrspimpl.h +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -216,7 +216,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( _Thread_Set_life_protection( initial_life_protection ); if ( timeout > 0 ) { - _Watchdog_Remove( &executing->Timer ); + _Watchdog_Remove_ticks( &executing->Timer ); } return status; diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index e548e7025c..ddd1ca4d1b 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -99,10 +99,12 @@ void _Watchdog_Handler_initialization( void ); * This routine removes @a the_watchdog from the watchdog chain on which * it resides and returns the state @a the_watchdog timer was in. * + * @param[in] header The watchdog chain. * @param[in] the_watchdog will be removed * @retval the state in which @a the_watchdog was in when removed */ Watchdog_States _Watchdog_Remove ( + Watchdog_Header *header, Watchdog_Control *the_watchdog ); @@ -306,6 +308,20 @@ RTEMS_INLINE_ROUTINE void _Watchdog_Insert_seconds( } +RTEMS_INLINE_ROUTINE Watchdog_States _Watchdog_Remove_ticks( + Watchdog_Control *the_watchdog +) +{ + return _Watchdog_Remove( &_Watchdog_Ticks_header, the_watchdog ); +} + +RTEMS_INLINE_ROUTINE Watchdog_States _Watchdog_Remove_seconds( + Watchdog_Control *the_watchdog +) +{ + return _Watchdog_Remove( &_Watchdog_Seconds_header, the_watchdog ); +} + /** * This routine resets THE_WATCHDOG timer to its state at INSERT * time. This routine is valid only on interval watchdog timers @@ -318,7 +334,7 @@ RTEMS_INLINE_ROUTINE void _Watchdog_Reset_ticks( ) { - (void) _Watchdog_Remove( the_watchdog ); + _Watchdog_Remove_ticks( the_watchdog ); _Watchdog_Insert( &_Watchdog_Ticks_header, the_watchdog ); diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 5f94ec99c9..590865d8dd 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -66,7 +66,7 @@ static void _Thread_blocking_operation_Finalize( if ( _Watchdog_Is_active( &the_thread->Timer ) ) { _Watchdog_Deactivate( &the_thread->Timer ); _Thread_queue_Release( lock_context ); - (void) _Watchdog_Remove( &the_thread->Timer ); + _Watchdog_Remove_ticks( &the_thread->Timer ); } else _Thread_queue_Release( lock_context ); diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index e759b5b42b..8dea518e10 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -62,7 +62,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( &the_thread->Timer ); + _Watchdog_Remove_ticks( &the_thread->Timer ); _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context ); _Chain_Append_unprotected( &zombies->Chain, &the_thread->Object.Node ); @@ -235,7 +235,7 @@ static void _Thread_Start_life_change( _Thread_Set_state( the_thread, STATES_RESTARTING ); _Thread_queue_Extract_with_proxy( the_thread ); - _Watchdog_Remove( &the_thread->Timer ); + _Watchdog_Remove_ticks( &the_thread->Timer ); _Scheduler_Set_priority_if_higher( scheduler, the_thread, priority ); _Thread_Add_post_switch_action( the_thread, &the_thread->Life.Action ); _Thread_Ready( the_thread ); diff --git a/cpukit/score/src/watchdogremove.c b/cpukit/score/src/watchdogremove.c index 34d97b0eae..d689e3cfc9 100644 --- a/cpukit/score/src/watchdogremove.c +++ b/cpukit/score/src/watchdogremove.c @@ -23,6 +23,7 @@ #include Watchdog_States _Watchdog_Remove( + Watchdog_Header *header, Watchdog_Control *the_watchdog ) { diff --git a/cpukit/score/src/watchdogtickle.c b/cpukit/score/src/watchdogtickle.c index 8c1a3a74b9..5b2f2582fc 100644 --- a/cpukit/score/src/watchdogtickle.c +++ b/cpukit/score/src/watchdogtickle.c @@ -74,7 +74,7 @@ void _Watchdog_Tickle( } do { - watchdog_state = _Watchdog_Remove( the_watchdog ); + watchdog_state = _Watchdog_Remove( header, the_watchdog ); _ISR_Enable( level ); diff --git a/testsuites/sptests/spintrcritical08/init.c b/testsuites/sptests/spintrcritical08/init.c index 13544b24c7..f375cd49f3 100644 --- a/testsuites/sptests/spintrcritical08/init.c +++ b/testsuites/sptests/spintrcritical08/init.c @@ -55,7 +55,7 @@ static rtems_timer_service_routine test_release_from_isr( watchdog->delta_interval == 0 && watchdog->routine == _Rate_monotonic_Timeout ) { - Watchdog_States state = _Watchdog_Remove( watchdog ); + Watchdog_States state = _Watchdog_Remove_ticks( watchdog ); rtems_test_assert( state == WATCHDOG_ACTIVE ); (*watchdog->routine)( watchdog->id, watchdog->user_data ); diff --git a/testsuites/sptests/spintrcritical09/init.c b/testsuites/sptests/spintrcritical09/init.c index 2f9caa5ad6..0e38351d43 100644 --- a/testsuites/sptests/spintrcritical09/init.c +++ b/testsuites/sptests/spintrcritical09/init.c @@ -52,7 +52,7 @@ static rtems_timer_service_routine test_release_from_isr( watchdog->delta_interval == 0 && watchdog->routine == _Thread_queue_Timeout ) { - Watchdog_States state = _Watchdog_Remove( watchdog ); + Watchdog_States state = _Watchdog_Remove_ticks( watchdog ); rtems_test_assert( state == WATCHDOG_ACTIVE ); (*watchdog->routine)( watchdog->id, watchdog->user_data ); -- cgit v1.2.3 From 6d2539413bcc0be45b6fb40e93b4012a1d91b58f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 15 Apr 2015 16:28:42 +0200 Subject: score: Add _Watchdog_Acquire|Release|Flash() Update #2307. --- cpukit/score/include/rtems/score/watchdogimpl.h | 30 +++++++++++++++++++++++++ cpukit/score/src/watchdogadjust.c | 16 ++++++------- cpukit/score/src/watchdogadjusttochain.c | 8 +++---- cpukit/score/src/watchdoginsert.c | 10 ++++----- cpukit/score/src/watchdogremove.c | 6 ++--- cpukit/score/src/watchdogtickle.c | 12 +++++----- 6 files changed, 56 insertions(+), 26 deletions(-) diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index ddd1ca4d1b..f52b55d83c 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -21,6 +21,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -48,6 +49,11 @@ extern "C" { * @brief Watchdog header. */ typedef struct { + /** + * @brief ISR lock to protect this watchdog chain. + */ + ISR_LOCK_MEMBER( Lock ) + /** * @brief The chain of active or transient watchdogs. */ @@ -84,6 +90,30 @@ SCORE_EXTERN Watchdog_Header _Watchdog_Ticks_header; */ SCORE_EXTERN Watchdog_Header _Watchdog_Seconds_header; +RTEMS_INLINE_ROUTINE void _Watchdog_Acquire( + Watchdog_Header *header, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_ISR_disable_and_acquire( &header->Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Watchdog_Release( + Watchdog_Header *header, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Release_and_ISR_enable( &header->Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Watchdog_Flash( + Watchdog_Header *header, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Flash( &header->Lock, lock_context ); +} + /** * @brief Initialize the watchdog handler. * diff --git a/cpukit/score/src/watchdogadjust.c b/cpukit/score/src/watchdogadjust.c index 687f063482..04fc1a55a7 100644 --- a/cpukit/score/src/watchdogadjust.c +++ b/cpukit/score/src/watchdogadjust.c @@ -27,15 +27,15 @@ void _Watchdog_Adjust_backward( Watchdog_Interval units ) { - ISR_Level level; + ISR_lock_Context lock_context; - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); if ( !_Watchdog_Is_empty( header ) ) { _Watchdog_First( header )->delta_interval += units; } - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); } void _Watchdog_Adjust_forward( @@ -43,9 +43,9 @@ void _Watchdog_Adjust_forward( Watchdog_Interval units ) { - ISR_Level level; + ISR_lock_Context lock_context; - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); while ( !_Watchdog_Is_empty( header ) && units > 0 ) { Watchdog_Control *first = _Watchdog_First( header ); @@ -57,13 +57,13 @@ void _Watchdog_Adjust_forward( units -= first->delta_interval; first->delta_interval = 1; - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); _Watchdog_Tickle( header ); - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); } } - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdogadjusttochain.c b/cpukit/score/src/watchdogadjusttochain.c index 1926656ca3..b3063e4109 100644 --- a/cpukit/score/src/watchdogadjusttochain.c +++ b/cpukit/score/src/watchdogadjusttochain.c @@ -29,10 +29,10 @@ void _Watchdog_Adjust_to_chain( ) { Watchdog_Interval units = units_arg; - ISR_Level level; + ISR_lock_Context lock_context; Watchdog_Control *first; - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); while ( 1 ) { if ( _Watchdog_Is_empty( header ) ) { @@ -60,7 +60,7 @@ void _Watchdog_Adjust_to_chain( _Chain_Extract_unprotected( &first->Node ); _Chain_Append_unprotected( to_fire, &first->Node ); - _ISR_Flash( level ); + _Watchdog_Flash( header, &lock_context ); if ( _Watchdog_Is_empty( header ) ) break; @@ -70,6 +70,6 @@ void _Watchdog_Adjust_to_chain( } } - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c index 272cac8db1..0ad59ff61a 100644 --- a/cpukit/score/src/watchdoginsert.c +++ b/cpukit/score/src/watchdoginsert.c @@ -27,7 +27,7 @@ void _Watchdog_Insert( Watchdog_Control *the_watchdog ) { - ISR_Level level; + ISR_lock_Context lock_context; Watchdog_Control *after; uint32_t insert_isr_nest_level; Watchdog_Interval delta_interval; @@ -35,7 +35,7 @@ void _Watchdog_Insert( insert_isr_nest_level = _ISR_Nest_level; - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); /* * Check to see if the watchdog has just been inserted by a @@ -43,7 +43,7 @@ void _Watchdog_Insert( */ if ( the_watchdog->state != WATCHDOG_INACTIVE ) { - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); return; } @@ -67,7 +67,7 @@ restart: delta_interval -= after->delta_interval; - _ISR_Flash( level ); + _Watchdog_Flash( header, &lock_context ); if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { goto exit_insert; @@ -90,5 +90,5 @@ restart: exit_insert: _Watchdog_Sync_level = insert_isr_nest_level; _Watchdog_Sync_count--; - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdogremove.c b/cpukit/score/src/watchdogremove.c index d689e3cfc9..c765ac55c7 100644 --- a/cpukit/score/src/watchdogremove.c +++ b/cpukit/score/src/watchdogremove.c @@ -27,11 +27,11 @@ Watchdog_States _Watchdog_Remove( Watchdog_Control *the_watchdog ) { - ISR_Level level; + ISR_lock_Context lock_context; Watchdog_States previous_state; Watchdog_Control *next_watchdog; - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); previous_state = the_watchdog->state; switch ( previous_state ) { case WATCHDOG_INACTIVE: @@ -63,6 +63,6 @@ Watchdog_States _Watchdog_Remove( } the_watchdog->stop_time = _Watchdog_Ticks_since_boot; - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); return( previous_state ); } diff --git a/cpukit/score/src/watchdogtickle.c b/cpukit/score/src/watchdogtickle.c index 5b2f2582fc..2092010dcc 100644 --- a/cpukit/score/src/watchdogtickle.c +++ b/cpukit/score/src/watchdogtickle.c @@ -25,9 +25,9 @@ void _Watchdog_Tickle( Watchdog_Header *header ) { - ISR_Level level; + ISR_lock_Context lock_context; Watchdog_Control *the_watchdog; - Watchdog_States watchdog_state; + Watchdog_States watchdog_state; /* * See the comment in watchdoginsert.c and watchdogadjust.c @@ -35,7 +35,7 @@ void _Watchdog_Tickle( * volatile data - till, 2003/7 */ - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); if ( _Watchdog_Is_empty( header ) ) goto leave; @@ -76,7 +76,7 @@ void _Watchdog_Tickle( do { watchdog_state = _Watchdog_Remove( header, the_watchdog ); - _ISR_Enable( level ); + _Watchdog_Release( header, &lock_context ); switch( watchdog_state ) { case WATCHDOG_ACTIVE: @@ -106,12 +106,12 @@ void _Watchdog_Tickle( break; } - _ISR_Disable( level ); + _Watchdog_Acquire( header, &lock_context ); the_watchdog = _Watchdog_First( header ); } while ( !_Watchdog_Is_empty( header ) && (the_watchdog->delta_interval == 0) ); leave: - _ISR_Enable(level); + _Watchdog_Release( header, &lock_context ); } -- cgit v1.2.3 From 1ccbd052910ed16131c74b0d5595c8a94066942d Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 15 Apr 2015 10:53:29 +0200 Subject: score: Add Watchdog_Iterator Rewrite the _Watchdog_Insert(), _Watchdog_Remove() and _Watchdog_Tickle() functions to use iterator items to synchronize concurrent operations. This makes it possible to get rid of the global variables _Watchdog_Sync_level and _Watchdog_Sync_count which are a blocking point for scalable SMP solutions. Update #2307. --- cpukit/rtems/src/timercreate.c | 6 + cpukit/score/include/rtems/score/watchdogimpl.h | 58 +++++++--- cpukit/score/src/watchdog.c | 2 - cpukit/score/src/watchdoginsert.c | 112 +++++++++++-------- cpukit/score/src/watchdogremove.c | 71 +++++++++--- cpukit/score/src/watchdogtickle.c | 139 +++++++++--------------- testsuites/sptests/spsize/size.c | 4 +- testsuites/sptests/spwatchdog/init.c | 114 +++++++++++++++++++ 8 files changed, 337 insertions(+), 169 deletions(-) diff --git a/cpukit/rtems/src/timercreate.c b/cpukit/rtems/src/timercreate.c index 2c6d251b8a..13a01feda9 100644 --- a/cpukit/rtems/src/timercreate.c +++ b/cpukit/rtems/src/timercreate.c @@ -29,6 +29,10 @@ void _Timer_Cancel( Timer_Control *the_timer ) { Timer_server_Control *timer_server; + ISR_Level level; + + /* The timer class must not change during the cancel operation */ + _ISR_Disable( level ); switch ( the_timer->the_class ) { case TIMER_INTERVAL: @@ -46,6 +50,8 @@ void _Timer_Cancel( Timer_Control *the_timer ) _Assert( the_timer->the_class == TIMER_DORMANT ); break; } + + _ISR_Enable( level ); } rtems_status_code rtems_timer_create( diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index f52b55d83c..304392b46c 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -45,6 +45,28 @@ extern "C" { ( routine ), ( id ), ( user_data ) \ } +/** + * @brief Iterator item to synchronize concurrent insert, remove and tickle + * operations. + */ +typedef struct { + /** + * @brief A node for a Watchdog_Header::Iterators chain. + */ + Chain_Node Node; + + /** + * @brief The current delta interval of the new watchdog to insert. + */ + Watchdog_Interval delta_interval; + + /** + * @brief The current watchdog of the chain on the way to insert the new + * watchdog. + */ + Chain_Node *current; +} Watchdog_Iterator; + /** * @brief Watchdog header. */ @@ -58,23 +80,15 @@ typedef struct { * @brief The chain of active or transient watchdogs. */ Chain_Control Watchdogs; -} Watchdog_Header; - -/** - * @brief Watchdog synchronization level. - * - * This used for synchronization purposes - * during an insert on a watchdog delta chain. - */ -SCORE_EXTERN volatile uint32_t _Watchdog_Sync_level; -/** - * @brief Watchdog synchronization count. - * - * This used for synchronization purposes - * during an insert on a watchdog delta chain. - */ -SCORE_EXTERN volatile uint32_t _Watchdog_Sync_count; + /** + * @brief Currently active iterators. + * + * The iterators are registered in _Watchdog_Insert() and updated in case the + * watchdog chain changes. + */ + Chain_Control Iterators; +} Watchdog_Header; /** * @brief Watchdog chain which is managed at ticks. @@ -138,6 +152,16 @@ Watchdog_States _Watchdog_Remove ( Watchdog_Control *the_watchdog ); +/** + * @brief Actually removes an WATCHDOG_ACTIVE or WATCHDOG_REMOVE_IT watchdog. + * + * @see _Watchdog_Remove() and _Watchdog_Tickle(). + */ +void _Watchdog_Remove_it( + Watchdog_Header *header, + Watchdog_Control *the_watchdog +); + /** * @brief Adjusts the header watchdog chain in the backward direction for * units ticks. @@ -437,7 +461,9 @@ RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize( Watchdog_Header *header ) { + _ISR_lock_Initialize( &header->Lock, "Watchdog" ); _Chain_Initialize_empty( &header->Watchdogs ); + _Chain_Initialize_empty( &header->Iterators ); } /** @} */ diff --git a/cpukit/score/src/watchdog.c b/cpukit/score/src/watchdog.c index 0db60efe6b..11d3cf289f 100644 --- a/cpukit/score/src/watchdog.c +++ b/cpukit/score/src/watchdog.c @@ -25,8 +25,6 @@ void _Watchdog_Handler_initialization( void ) { - _Watchdog_Sync_count = 0; - _Watchdog_Sync_level = 0; _Watchdog_Ticks_since_boot = 0; _Watchdog_Header_initialize( &_Watchdog_Ticks_header ); diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c index 0ad59ff61a..6d2df8222f 100644 --- a/cpukit/score/src/watchdoginsert.c +++ b/cpukit/score/src/watchdoginsert.c @@ -19,76 +19,92 @@ #endif #include -#include -#include -void _Watchdog_Insert( - Watchdog_Header *header, - Watchdog_Control *the_watchdog +static void _Watchdog_Insert_fixup( + Watchdog_Header *header, + Watchdog_Control *next_watchdog, + Watchdog_Interval delta ) { - ISR_lock_Context lock_context; - Watchdog_Control *after; - uint32_t insert_isr_nest_level; - Watchdog_Interval delta_interval; + const Chain_Node *iterator_tail; + Chain_Node *iterator_node; + next_watchdog->delta_interval -= delta; - insert_isr_nest_level = _ISR_Nest_level; + iterator_node = _Chain_First( &header->Iterators ); + iterator_tail = _Chain_Immutable_tail( &header->Iterators ); - _Watchdog_Acquire( header, &lock_context ); + while ( iterator_node != iterator_tail ) { + Watchdog_Iterator *iterator; - /* - * Check to see if the watchdog has just been inserted by a - * higher priority interrupt. If so, abandon this insert. - */ + iterator = (Watchdog_Iterator *) iterator_node; - if ( the_watchdog->state != WATCHDOG_INACTIVE ) { - _Watchdog_Release( header, &lock_context ); - return; + if ( iterator->current == &next_watchdog->Node ) { + iterator->delta_interval -= delta; + } + + iterator_node = _Chain_Next( iterator_node ); } +} - the_watchdog->state = WATCHDOG_BEING_INSERTED; - _Watchdog_Sync_count++; +void _Watchdog_Insert( + Watchdog_Header *header, + Watchdog_Control *the_watchdog +) +{ + ISR_lock_Context lock_context; -restart: - delta_interval = the_watchdog->initial; + _Watchdog_Acquire( header, &lock_context ); - for ( after = _Watchdog_First( header ) ; - ; - after = _Watchdog_Next( after ) ) { + if ( the_watchdog->state == WATCHDOG_INACTIVE ) { + Watchdog_Iterator iterator; + Chain_Node *current; + Chain_Node *next; + Watchdog_Interval delta; - if ( delta_interval == 0 || !_Watchdog_Next( after ) ) - break; + the_watchdog->state = WATCHDOG_BEING_INSERTED; - if ( delta_interval < after->delta_interval ) { - after->delta_interval -= delta_interval; - break; - } + _Chain_Append_unprotected( &header->Iterators, &iterator.Node ); - delta_interval -= after->delta_interval; + delta = the_watchdog->initial; + current = _Chain_Head( &header->Watchdogs ); - _Watchdog_Flash( header, &lock_context ); + while ( + ( next = _Chain_Next( current ) ) != _Chain_Tail( &header->Watchdogs ) + ) { + Watchdog_Control *next_watchdog; + Watchdog_Interval delta_next; - if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { - goto exit_insert; - } + next_watchdog = (Watchdog_Control *) next; + delta_next = next_watchdog->delta_interval; - if ( _Watchdog_Sync_level > insert_isr_nest_level ) { - _Watchdog_Sync_level = insert_isr_nest_level; - goto restart; - } - } + if ( delta < delta_next ) { + _Watchdog_Insert_fixup( header, next_watchdog, delta ); + break; + } + + iterator.delta_interval = delta - delta_next; + iterator.current = next; - _Watchdog_Activate( the_watchdog ); + _Watchdog_Flash( header, &lock_context ); - the_watchdog->delta_interval = delta_interval; + if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { + goto abort_insert; + } - _Chain_Insert_unprotected( after->Node.previous, &the_watchdog->Node ); + delta = iterator.delta_interval; + current = iterator.current; + } - the_watchdog->start_time = _Watchdog_Ticks_since_boot; + 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 ); + } -exit_insert: - _Watchdog_Sync_level = insert_isr_nest_level; - _Watchdog_Sync_count--; _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdogremove.c b/cpukit/score/src/watchdogremove.c index c765ac55c7..c896fbb00f 100644 --- a/cpukit/score/src/watchdogremove.c +++ b/cpukit/score/src/watchdogremove.c @@ -18,9 +18,58 @@ #include "config.h" #endif -#include -#include #include +#include + +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_REMOVE_IT + ); + + 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 ) { + iterator->current = _Chain_Previous( &the_watchdog->Node ); + } + + iterator_node = _Chain_Next( iterator_node ); + } +} Watchdog_States _Watchdog_Remove( Watchdog_Header *header, @@ -29,7 +78,7 @@ Watchdog_States _Watchdog_Remove( { ISR_lock_Context lock_context; Watchdog_States previous_state; - Watchdog_Control *next_watchdog; + Watchdog_Interval now; _Watchdog_Acquire( header, &lock_context ); previous_state = the_watchdog->state; @@ -44,24 +93,16 @@ Watchdog_States _Watchdog_Remove( * 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: case WATCHDOG_REMOVE_IT: - - the_watchdog->state = WATCHDOG_INACTIVE; - next_watchdog = _Watchdog_Next( the_watchdog ); - - if ( _Watchdog_Next(next_watchdog) ) - next_watchdog->delta_interval += the_watchdog->delta_interval; - - if ( _Watchdog_Sync_count ) - _Watchdog_Sync_level = _ISR_Nest_level; - - _Chain_Extract_unprotected( &the_watchdog->Node ); + _Watchdog_Remove_it( header, the_watchdog ); break; } - the_watchdog->stop_time = _Watchdog_Ticks_since_boot; _Watchdog_Release( header, &lock_context ); return( previous_state ); diff --git a/cpukit/score/src/watchdogtickle.c b/cpukit/score/src/watchdogtickle.c index 2092010dcc..7a80008c4d 100644 --- a/cpukit/score/src/watchdogtickle.c +++ b/cpukit/score/src/watchdogtickle.c @@ -19,99 +19,68 @@ #endif #include -#include void _Watchdog_Tickle( Watchdog_Header *header ) { - ISR_lock_Context lock_context; - Watchdog_Control *the_watchdog; - Watchdog_States watchdog_state; - - /* - * See the comment in watchdoginsert.c and watchdogadjust.c - * about why it's safe not to declare header a pointer to - * volatile data - till, 2003/7 - */ + ISR_lock_Context lock_context; _Watchdog_Acquire( header, &lock_context ); - if ( _Watchdog_Is_empty( header ) ) - goto leave; - - the_watchdog = _Watchdog_First( header ); - - /* - * For some reason, on rare occasions the_watchdog->delta_interval - * of the head of the watchdog chain is 0. Before this test was - * added, on these occasions an event (which usually was supposed - * to have a timeout of 1 tick would have a delta_interval of 0, which - * would be decremented to 0xFFFFFFFF by the unprotected - * "the_watchdog->delta_interval--;" operation. - * This would mean the event would not timeout, and also the chain would - * be blocked, because a timeout with a very high number would be at the - * head, rather than at the end. - * The test "if (the_watchdog->delta_interval != 0)" - * here prevents this from occuring. - * - * We were not able to categorically identify the situation that causes - * this, but proved it to be true empirically. So this check causes - * correct behaviour in this circumstance. - * - * The belief is that a race condition exists whereby an event at the head - * of the chain is removed (by a pending ISR or higher priority task) - * during the _ISR_Flash( level ); in _Watchdog_Insert, but the watchdog - * to be inserted has already had its delta_interval adjusted to 0, and - * so is added to the head of the chain with a delta_interval of 0. - * - * Steven Johnson - 12/2005 (gcc-3.2.3 -O3 on powerpc) - */ - if (the_watchdog->delta_interval != 0) { - the_watchdog->delta_interval--; - if ( the_watchdog->delta_interval != 0 ) - goto leave; + 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; + } + + 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; + } } - do { - watchdog_state = _Watchdog_Remove( header, the_watchdog ); - - _Watchdog_Release( header, &lock_context ); - - switch( watchdog_state ) { - case WATCHDOG_ACTIVE: - (*the_watchdog->routine)( - the_watchdog->id, - the_watchdog->user_data - ); - break; - - case WATCHDOG_INACTIVE: - /* - * This state indicates that the watchdog is not on any chain. - * Thus, it is NOT on a chain being tickled. This case should - * never occur. - */ - break; - - case WATCHDOG_BEING_INSERTED: - /* - * This state indicates that the watchdog is in the process of - * BEING inserted on the chain. Thus, it can NOT be on a chain - * being tickled. This case should never occur. - */ - break; - - case WATCHDOG_REMOVE_IT: - break; - } - - _Watchdog_Acquire( header, &lock_context ); - - the_watchdog = _Watchdog_First( header ); - } while ( !_Watchdog_Is_empty( header ) && - (the_watchdog->delta_interval == 0) ); - -leave: - _Watchdog_Release( header, &lock_context ); + _Watchdog_Release( header, &lock_context ); } diff --git a/testsuites/sptests/spsize/size.c b/testsuites/sptests/spsize/size.c index f00da0d465..58bcc89312 100644 --- a/testsuites/sptests/spsize/size.c +++ b/testsuites/sptests/spsize/size.c @@ -399,9 +399,7 @@ uninitialized = /*userext.h*/ (sizeof _User_extensions_List) + -/*watchdog.h*/ (sizeof _Watchdog_Sync_level) + - (sizeof _Watchdog_Sync_count) + - (sizeof _Watchdog_Ticks_since_boot) + +/*watchdog.h*/ (sizeof _Watchdog_Ticks_since_boot) + (sizeof _Watchdog_Ticks_header) + (sizeof _Watchdog_Seconds_header) + diff --git a/testsuites/sptests/spwatchdog/init.c b/testsuites/sptests/spwatchdog/init.c index 1d3cb2f9dd..283f4c87a0 100644 --- a/testsuites/sptests/spwatchdog/init.c +++ b/testsuites/sptests/spwatchdog/init.c @@ -34,6 +34,119 @@ static void test_watchdog_routine( Objects_Id id, void *arg ) rtems_test_assert( 0 ); } +static void init_watchdogs( + Watchdog_Header *header, + Watchdog_Control watchdogs[3] +) +{ + Watchdog_Control *a = &watchdogs[0]; + Watchdog_Control *b = &watchdogs[1]; + Watchdog_Control *c = &watchdogs[2]; + Watchdog_Control *d = &watchdogs[3]; + + _Watchdog_Header_initialize( header ); + rtems_test_assert( _Watchdog_Is_empty( header ) ); + rtems_test_assert( _Chain_Is_empty( &header->Iterators ) ); + + _Watchdog_Initialize( c, NULL, 0, NULL ); + c->initial = 6; + _Watchdog_Insert( header, c ); + rtems_test_assert( c->delta_interval == 6 ); + + rtems_test_assert( !_Watchdog_Is_empty( header ) ); + rtems_test_assert( _Chain_Is_empty( &header->Iterators ) ); + + _Watchdog_Initialize( a, NULL, 0, NULL ); + a->initial = 2; + _Watchdog_Insert( header, a ); + rtems_test_assert( a->delta_interval == 2 ); + rtems_test_assert( c->delta_interval == 4 ); + + _Watchdog_Initialize( b, NULL, 0, NULL ); + b->initial = 4; + _Watchdog_Insert( header, b ); + rtems_test_assert( a->delta_interval == 2 ); + rtems_test_assert( b->delta_interval == 2 ); + rtems_test_assert( c->delta_interval == 2 ); + + _Watchdog_Initialize( d, NULL, 0, NULL ); +} + +static void destroy_watchdogs( + Watchdog_Header *header +) +{ + _ISR_lock_Destroy( &header->Lock ); +} + +static void add_iterator( + Watchdog_Header *header, + Watchdog_Iterator *i, + Watchdog_Control *w +) +{ + _Chain_Append_unprotected( &header->Iterators, &i->Node ); + i->delta_interval = 2; + i->current = &w->Node; +} + +static void test_watchdog_insert_and_remove( void ) +{ + Watchdog_Header header; + Watchdog_Control watchdogs[4]; + Watchdog_Control *a = &watchdogs[0]; + Watchdog_Control *b = &watchdogs[1]; + Watchdog_Control *c = &watchdogs[2]; + Watchdog_Control *d = &watchdogs[3]; + Watchdog_Iterator i; + + init_watchdogs( &header, watchdogs ); + add_iterator( &header, &i, c ); + + /* Remove next watchdog of iterator */ + _Watchdog_Remove( &header, c ); + rtems_test_assert( i.delta_interval == 2 ); + rtems_test_assert( i.current == &b->Node ); + + /* Remove watchdog before the current watchdog of iterator */ + _Watchdog_Remove( &header, a ); + rtems_test_assert( i.delta_interval == 4 ); + rtems_test_assert( i.current == &b->Node ); + + /* Remove current (= last) watchdog of iterator */ + _Watchdog_Remove( &header, b ); + rtems_test_assert( i.delta_interval == 4 ); + rtems_test_assert( i.current == _Chain_Head( &header.Watchdogs ) ); + + /* Insert first watchdog */ + a->initial = 1; + _Watchdog_Insert( &header, a ); + rtems_test_assert( i.delta_interval == 4 ); + rtems_test_assert( i.current == _Chain_Head( &header.Watchdogs ) ); + + destroy_watchdogs( &header ); + init_watchdogs( &header, watchdogs ); + add_iterator( &header, &i, b ); + + /* Insert right before current watchdog of iterator */ + d->initial = 3; + _Watchdog_Insert( &header, d ); + rtems_test_assert( i.delta_interval == 1 ); + rtems_test_assert( i.current == &b->Node ); + + destroy_watchdogs( &header ); + init_watchdogs( &header, watchdogs ); + add_iterator( &header, &i, b ); + + /* Insert right after current watchdog of iterator */ + d->initial = 5; + _Watchdog_Insert( &header, d ); + rtems_test_assert( i.delta_interval == 2 ); + rtems_test_assert( i.current == &b->Node ); + + destroy_watchdogs( &header ); +} + static void test_watchdog_static_init( void ) { #if defined(RTEMS_USE_16_BIT_OBJECT) @@ -70,6 +183,7 @@ rtems_task Init( TEST_BEGIN(); test_watchdog_static_init(); + test_watchdog_insert_and_remove(); build_time( &time, 12, 31, 1988, 9, 0, 0, 0 ); -- cgit v1.2.3 From fd53d2514e8869dd5ddb5fd5a72f6f443840cca8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 24 Apr 2015 09:53:58 +0200 Subject: score: Move _Watchdog_Tickle() Make internal function _Watchdog_Remove_it() static to avoid accidental usage. Update #2307. --- cpukit/score/Makefile.am | 3 +- cpukit/score/include/rtems/score/watchdogimpl.h | 10 --- cpukit/score/src/watchdogremove.c | 67 ++++++++++++++++++- cpukit/score/src/watchdogtickle.c | 86 ------------------------- 4 files changed, 67 insertions(+), 99 deletions(-) delete mode 100644 cpukit/score/src/watchdogtickle.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index f8ad60da3a..af7da2ac53 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -324,8 +324,7 @@ libscore_a_SOURCES += src/coretod.c src/coretodset.c src/coretodget.c \ ## WATCHDOG_C_FILES libscore_a_SOURCES += src/watchdog.c src/watchdogadjust.c \ - src/watchdogadjusttochain.c src/watchdoginsert.c src/watchdogremove.c \ - src/watchdogtickle.c + src/watchdogadjusttochain.c src/watchdoginsert.c src/watchdogremove.c libscore_a_SOURCES += src/watchdogtickssinceboot.c ## USEREXT_C_FILES diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index 304392b46c..dfe50e6d3a 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -152,16 +152,6 @@ Watchdog_States _Watchdog_Remove ( Watchdog_Control *the_watchdog ); -/** - * @brief Actually removes an WATCHDOG_ACTIVE or WATCHDOG_REMOVE_IT watchdog. - * - * @see _Watchdog_Remove() and _Watchdog_Tickle(). - */ -void _Watchdog_Remove_it( - Watchdog_Header *header, - Watchdog_Control *the_watchdog -); - /** * @brief Adjusts the header watchdog chain in the backward direction for * units ticks. diff --git a/cpukit/score/src/watchdogremove.c b/cpukit/score/src/watchdogremove.c index c896fbb00f..2ac63fe998 100644 --- a/cpukit/score/src/watchdogremove.c +++ b/cpukit/score/src/watchdogremove.c @@ -21,7 +21,7 @@ #include #include -void _Watchdog_Remove_it( +static void _Watchdog_Remove_it( Watchdog_Header *header, Watchdog_Control *the_watchdog ) @@ -107,3 +107,68 @@ Watchdog_States _Watchdog_Remove( _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; + } + + 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; + } + } + + _Watchdog_Release( header, &lock_context ); +} diff --git a/cpukit/score/src/watchdogtickle.c b/cpukit/score/src/watchdogtickle.c deleted file mode 100644 index 7a80008c4d..0000000000 --- a/cpukit/score/src/watchdogtickle.c +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file - * - * @ingroup ScoreWatchdog - * @brief Watchdog Tickle - */ - -/* - * 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 - -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; - } - - 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; - } - } - - _Watchdog_Release( header, &lock_context ); -} -- cgit v1.2.3 From a382010c62455df73552eb5f0baa1faebe9702c7 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 10 Apr 2015 15:31:31 +0200 Subject: score: New timer server implementation Use mostly the standard watchdog operations. Use a system event for synchronization. This implementation is simpler and offers better SMP performance. Close #2131. --- cpukit/rtems/include/rtems/rtems/event.h | 5 + cpukit/rtems/include/rtems/rtems/timerimpl.h | 51 +- cpukit/rtems/src/timerserver.c | 570 +++++++-------------- cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/watchdogimpl.h | 59 ++- cpukit/score/src/watchdogadjust.c | 35 +- cpukit/score/src/watchdogadjusttochain.c | 75 --- cpukit/score/src/watchdoginsert.c | 21 +- testsuites/sptests/spintrcritical17/init.c | 163 +++--- .../sptests/spintrcritical17/spintrcritical17.doc | 6 +- 10 files changed, 370 insertions(+), 617 deletions(-) delete mode 100644 cpukit/score/src/watchdogadjusttochain.c diff --git a/cpukit/rtems/include/rtems/rtems/event.h b/cpukit/rtems/include/rtems/rtems/event.h index dce7de1165..012452a9d8 100644 --- a/cpukit/rtems/include/rtems/rtems/event.h +++ b/cpukit/rtems/include/rtems/rtems/event.h @@ -318,6 +318,11 @@ rtems_status_code rtems_event_receive ( */ #define RTEMS_EVENT_SYSTEM_NETWORK_CLOSE RTEMS_EVENT_26 +/** + * @brief Reserved system event for the timer server. + */ +#define RTEMS_EVENT_SYSTEM_TIMER_SERVER RTEMS_EVENT_30 + /** * @brief Reserved system event for transient usage. */ diff --git a/cpukit/rtems/include/rtems/rtems/timerimpl.h b/cpukit/rtems/include/rtems/rtems/timerimpl.h index 4f200efb75..e5b37aa5f1 100644 --- a/cpukit/rtems/include/rtems/rtems/timerimpl.h +++ b/cpukit/rtems/include/rtems/rtems/timerimpl.h @@ -64,25 +64,44 @@ typedef struct { */ Watchdog_Control System_watchdog; + /** + * @brief Remaining delta of the system watchdog. + */ + Watchdog_Interval system_watchdog_delta; + + /** + * @brief Unique identifier of the context which deals currently with the + * system watchdog. + */ + Thread_Control *system_watchdog_helper; + + /** + * @brief Each insert and tickle operation increases the generation count so + * that the system watchdog dealer notices updates of the watchdog chain. + */ + uint32_t generation; + /** * @brief Watchdog header managed by the timer server. */ Watchdog_Header Header; /** - * @brief Last known time snapshot of the timer server. + * @brief Last time snapshot of the timer server. * * The units may be ticks or seconds. */ - Watchdog_Interval volatile last_snapshot; -} Timer_server_Watchdogs; + Watchdog_Interval last_snapshot; -struct Timer_server_Control { /** - * @brief Timer server thread. + * @brief Current time snapshot of the timer server. + * + * The units may be ticks or seconds. */ - Thread_Control *thread; + Watchdog_Interval current_snapshot; +} Timer_server_Watchdogs; +struct Timer_server_Control { /** * @brief The cancel method of the timer server. */ @@ -102,26 +121,6 @@ struct Timer_server_Control { * @brief TOD watchdogs triggered by the timer server. */ Timer_server_Watchdogs TOD_watchdogs; - - /** - * @brief Chain of timers scheduled for insert. - * - * This pointer is not @c NULL whenever the interval and TOD chains are - * processed. After the processing this list will be checked and if - * necessary the processing will be restarted. Processing of these chains - * can be only interrupted through interrupts. - */ - Chain_Control *volatile insert_chain; - - /** - * @brief Indicates that the timer server is active or not. - * - * The server is active after the delay on a system watchdog. The activity - * period of the server ends when no more watchdogs managed by the server - * fire. The system watchdogs must not be manipulated when the server is - * active. - */ - bool volatile active; }; /** diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index 15cbdfd59f..db38f48484 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -15,7 +15,7 @@ /* COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2009 embedded brains GmbH. + * 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 @@ -26,200 +26,128 @@ #include "config.h" #endif +#include #include #include -#include -#include #include static Timer_server_Control _Timer_server_Default; -static void _Timer_server_Stop_interval_system_watchdog( - Timer_server_Control *ts +static void _Timer_server_Cancel_method( + Timer_server_Control *ts, + Timer_Control *timer ) { - _Watchdog_Remove_ticks( &ts->Interval_watchdogs.System_watchdog ); + if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { + _Watchdog_Remove( &ts->Interval_watchdogs.Header, &timer->Ticker ); + } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { + _Watchdog_Remove( &ts->TOD_watchdogs.Header, &timer->Ticker ); + } } -static void _Timer_server_Reset_interval_system_watchdog( - Timer_server_Control *ts -) +static Watchdog_Interval _Timer_server_Get_ticks( void ) { - ISR_Level level; - - _Timer_server_Stop_interval_system_watchdog( ts ); - - _ISR_Disable( level ); - if ( !_Watchdog_Is_empty( &ts->Interval_watchdogs.Header ) ) { - Watchdog_Interval delta_interval = - _Watchdog_First( &ts->Interval_watchdogs.Header )->delta_interval; - _ISR_Enable( level ); - - /* - * The unit is TICKS here. - */ - _Watchdog_Insert_ticks( - &ts->Interval_watchdogs.System_watchdog, - delta_interval - ); - } else { - _ISR_Enable( level ); - } + return _Watchdog_Ticks_since_boot; } -static void _Timer_server_Stop_tod_system_watchdog( - Timer_server_Control *ts -) +static Watchdog_Interval _Timer_server_Get_seconds( void ) { - _Watchdog_Remove_seconds( &ts->TOD_watchdogs.System_watchdog ); + return _TOD_Seconds_since_epoch(); } -static void _Timer_server_Reset_tod_system_watchdog( - Timer_server_Control *ts +static void _Timer_server_Update_system_watchdog( + Timer_server_Watchdogs *watchdogs, + Watchdog_Header *system_header ) { - ISR_Level level; + ISR_lock_Context lock_context; - _Timer_server_Stop_tod_system_watchdog( ts ); + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - _ISR_Disable( level ); - if ( !_Watchdog_Is_empty( &ts->TOD_watchdogs.Header ) ) { - Watchdog_Interval delta_interval = - _Watchdog_First( &ts->TOD_watchdogs.Header )->delta_interval; - _ISR_Enable( level ); + if ( watchdogs->system_watchdog_helper == NULL ) { + Thread_Control *executing; + uint32_t my_generation; - /* - * The unit is SECONDS here. - */ - _Watchdog_Insert_seconds( - &ts->TOD_watchdogs.System_watchdog, - delta_interval - ); - } else { - _ISR_Enable( level ); - } -} + executing = _Thread_Executing; + watchdogs->system_watchdog_helper = executing; -static void _Timer_server_Insert_timer( - Timer_server_Control *ts, - Timer_Control *timer -) -{ - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - _Watchdog_Insert( &ts->Interval_watchdogs.Header, &timer->Ticker ); - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - _Watchdog_Insert( &ts->TOD_watchdogs.Header, &timer->Ticker ); + do { + my_generation = watchdogs->generation; + + if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { + Watchdog_Control *first; + Watchdog_Interval delta; + + first = _Watchdog_First( &watchdogs->Header ); + delta = first->delta_interval; + + if ( + watchdogs->System_watchdog.state == WATCHDOG_INACTIVE + || delta != watchdogs->system_watchdog_delta + ) { + watchdogs->system_watchdog_delta = delta; + _Watchdog_Release( &watchdogs->Header, &lock_context ); + + _Watchdog_Remove( system_header, &watchdogs->System_watchdog ); + watchdogs->System_watchdog.initial = delta; + _Watchdog_Insert( system_header, &watchdogs->System_watchdog ); + + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); + } + } + } while ( watchdogs->generation != my_generation ); + + watchdogs->system_watchdog_helper = NULL; } + + _Watchdog_Release( &watchdogs->Header, &lock_context ); } -static void _Timer_server_Insert_timer_and_make_snapshot( - Timer_server_Control *ts, - Timer_Control *timer +static void _Timer_server_Insert_timer( + Timer_server_Watchdogs *watchdogs, + Timer_Control *timer, + Watchdog_Header *system_header, + Watchdog_Interval (*get_ticks)( void ) ) { - Watchdog_Control *first_watchdog; - Watchdog_Interval delta_interval; - Watchdog_Interval last_snapshot; - Watchdog_Interval snapshot; + ISR_lock_Context lock_context; + Watchdog_Interval now; Watchdog_Interval delta; - ISR_Level level; - /* - * We have to update the time snapshots here, because otherwise we may have - * problems with the integer range of the delta values. The time delta DT - * from the last snapshot to now may be arbitrarily long. The last snapshot - * is the reference point for the delta chain. Thus if we do not update the - * reference point we have to add DT to the initial delta of the watchdog - * being inserted. This could result in an integer overflow. - */ + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - _Thread_Disable_dispatch(); + now = (*get_ticks)(); + delta = now - watchdogs->last_snapshot; + watchdogs->last_snapshot = now; + watchdogs->current_snapshot = now; - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - /* - * We have to advance the last known ticks value of the server and update - * the watchdog chain accordingly. - */ - _ISR_Disable( level ); - snapshot = _Watchdog_Ticks_since_boot; - last_snapshot = ts->Interval_watchdogs.last_snapshot; - if ( !_Watchdog_Is_empty( &ts->Interval_watchdogs.Header ) ) { - first_watchdog = _Watchdog_First( &ts->Interval_watchdogs.Header ); - - /* - * We assume adequate unsigned arithmetic here. - */ - delta = snapshot - last_snapshot; - - delta_interval = first_watchdog->delta_interval; - if (delta_interval > delta) { - delta_interval -= delta; - } else { - delta_interval = 0; - } - first_watchdog->delta_interval = delta_interval; - } - ts->Interval_watchdogs.last_snapshot = snapshot; - _ISR_Enable( level ); + if ( watchdogs->system_watchdog_delta > delta ) { + watchdogs->system_watchdog_delta -= delta; + } else { + watchdogs->system_watchdog_delta = 0; + } - _Watchdog_Insert( &ts->Interval_watchdogs.Header, &timer->Ticker ); + if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { + Watchdog_Control *first = _Watchdog_First( &watchdogs->Header ); - if ( !ts->active ) { - _Timer_server_Reset_interval_system_watchdog( ts ); - } - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - /* - * We have to advance the last known seconds value of the server and update - * the watchdog chain accordingly. - */ - _ISR_Disable( level ); - snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); - last_snapshot = ts->TOD_watchdogs.last_snapshot; - if ( !_Watchdog_Is_empty( &ts->TOD_watchdogs.Header ) ) { - first_watchdog = _Watchdog_First( &ts->TOD_watchdogs.Header ); - delta_interval = first_watchdog->delta_interval; - if ( snapshot > last_snapshot ) { - /* - * We advanced in time. - */ - delta = snapshot - last_snapshot; - if (delta_interval > delta) { - delta_interval -= delta; - } else { - delta_interval = 0; - } - } else { - /* - * Someone put us in the past. - */ - delta = last_snapshot - snapshot; - delta_interval += delta; - } - first_watchdog->delta_interval = delta_interval; + if ( first->delta_interval > delta ) { + first->delta_interval -= delta; + } else { + first->delta_interval = 0; } - ts->TOD_watchdogs.last_snapshot = snapshot; - _ISR_Enable( level ); + } - _Watchdog_Insert( &ts->TOD_watchdogs.Header, &timer->Ticker ); + _Watchdog_Insert_locked( + &watchdogs->Header, + &timer->Ticker, + &lock_context + ); - if ( !ts->active ) { - _Timer_server_Reset_tod_system_watchdog( ts ); - } - } + ++watchdogs->generation; - _Thread_Enable_dispatch(); -} + _Watchdog_Release( &watchdogs->Header, &lock_context ); -static void _Timer_server_Cancel_method( - Timer_server_Control *ts, - Timer_Control *timer -) -{ - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - _Watchdog_Remove( &ts->Interval_watchdogs.Header, &timer->Ticker ); - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - _Watchdog_Remove( &ts->TOD_watchdogs.Header, &timer->Ticker ); - } + _Timer_server_Update_system_watchdog( watchdogs, system_header ); } static void _Timer_server_Schedule_operation_method( @@ -227,143 +155,71 @@ static void _Timer_server_Schedule_operation_method( Timer_Control *timer ) { - if ( ts->insert_chain == NULL ) { - _Timer_server_Insert_timer_and_make_snapshot( ts, timer ); - } else { - /* - * We interrupted a critical section of the timer server. The timer - * server is not preemptible, so we must be in interrupt context here. No - * thread dispatch will happen until the timer server finishes its - * critical section. We have to use the protected chain methods because - * we may be interrupted by a higher priority interrupt. - */ - _Chain_Append( ts->insert_chain, &timer->Object.Node ); + if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { + _Timer_server_Insert_timer( + &ts->Interval_watchdogs, + timer, + &_Watchdog_Ticks_header, + _Timer_server_Get_ticks + ); + } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { + _Timer_server_Insert_timer( + &ts->TOD_watchdogs, + timer, + &_Watchdog_Seconds_header, + _Timer_server_Get_seconds + ); } } -static void _Timer_server_Process_interval_watchdogs( +static void _Timer_server_Update_current_snapshot( Timer_server_Watchdogs *watchdogs, - Chain_Control *fire_chain + Watchdog_Interval (*get_ticks)( void ) ) { - Watchdog_Interval snapshot = _Watchdog_Ticks_since_boot; + ISR_lock_Context lock_context; - /* - * We assume adequate unsigned arithmetic here. - */ - Watchdog_Interval delta = snapshot - watchdogs->last_snapshot; - - watchdogs->last_snapshot = snapshot; - - _Watchdog_Adjust_to_chain( &watchdogs->Header, delta, fire_chain ); + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); + watchdogs->current_snapshot = (*get_ticks)(); + watchdogs->system_watchdog_delta = 0; + _Watchdog_Release( &watchdogs->Header, &lock_context ); } -static void _Timer_server_Process_tod_watchdogs( +static void _Timer_server_Tickle( Timer_server_Watchdogs *watchdogs, - Chain_Control *fire_chain + Watchdog_Header *system_header, + Watchdog_Interval (*get_ticks)( void ), + bool ticks ) { - Watchdog_Interval snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); - Watchdog_Interval last_snapshot = watchdogs->last_snapshot; - Watchdog_Interval delta; - - /* - * Process the seconds chain. Start by checking that the Time - * of Day (TOD) has not been set backwards. If it has then - * we want to adjust the watchdogs->Header to indicate this. - */ - if ( snapshot > last_snapshot ) { - /* - * This path is for normal forward movement and cases where the - * TOD has been set forward. - */ - delta = snapshot - last_snapshot; - _Watchdog_Adjust_to_chain( &watchdogs->Header, delta, fire_chain ); - - } else if ( snapshot < last_snapshot ) { - /* - * The current TOD is before the last TOD which indicates that - * TOD has been set backwards. - */ - delta = last_snapshot - snapshot; - _Watchdog_Adjust_backward( &watchdogs->Header, delta ); - } - - watchdogs->last_snapshot = snapshot; -} - -static void _Timer_server_Process_insertions( Timer_server_Control *ts ) -{ - while ( true ) { - Timer_Control *timer = (Timer_Control *) _Chain_Get( ts->insert_chain ); + ISR_lock_Context lock_context; + Watchdog_Interval now; + Watchdog_Interval last; - if ( timer == NULL ) { - break; - } - - _Timer_server_Insert_timer( ts, timer ); - } -} - -static void _Timer_server_Get_watchdogs_that_fire_now( - Timer_server_Control *ts, - Chain_Control *insert_chain, - Chain_Control *fire_chain -) -{ - /* - * Afterwards all timer inserts are directed to this chain and the interval - * and TOD chains will be no more modified by other parties. - */ - ts->insert_chain = insert_chain; + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - while ( true ) { - ISR_Level level; + now = watchdogs->current_snapshot; + last = watchdogs->last_snapshot; + watchdogs->last_snapshot = now; - /* - * Remove all the watchdogs that need to fire so we can invoke them. - */ - _Timer_server_Process_interval_watchdogs( - &ts->Interval_watchdogs, - fire_chain + if ( ticks || now >= last ) { + _Watchdog_Adjust_forward_locked( + &watchdogs->Header, + now - last, + &lock_context + ); + } else { + _Watchdog_Adjust_backward_locked( + &watchdogs->Header, + last - now ); - _Timer_server_Process_tod_watchdogs( &ts->TOD_watchdogs, fire_chain ); - - /* - * The insertions have to take place here, because they reference the - * current time. The previous process methods take a snapshot of the - * current time. In case someone inserts a watchdog with an initial value - * of zero it will be processed in the next iteration of the timer server - * body loop. - */ - _Timer_server_Process_insertions( ts ); - - _ISR_Disable( level ); - if ( _Chain_Is_empty( insert_chain ) ) { - ts->insert_chain = NULL; - _ISR_Enable( level ); - - break; - } else { - _ISR_Enable( level ); - } } -} -/* FIXME: This locking approach for SMP is improvable! */ + ++watchdogs->generation; -static void _Timer_server_SMP_lock_aquire( void ) -{ -#if defined( RTEMS_SMP ) - _Thread_Disable_dispatch(); -#endif -} + _Watchdog_Release( &watchdogs->Header, &lock_context ); -static void _Timer_server_SMP_lock_release( void ) -{ -#if defined( RTEMS_SMP ) - _Thread_Enable_dispatch(); -#endif + _Timer_server_Update_system_watchdog( watchdogs, system_header ); } /** @@ -380,81 +236,73 @@ static rtems_task _Timer_server_Body( ) { Timer_server_Control *ts = (Timer_server_Control *) arg; - Chain_Control insert_chain; - Chain_Control fire_chain; - _Chain_Initialize_empty( &insert_chain ); - _Chain_Initialize_empty( &fire_chain ); + while ( true ) { + rtems_event_set events; - _Timer_server_SMP_lock_aquire(); + _Timer_server_Tickle( + &ts->Interval_watchdogs, + &_Watchdog_Ticks_header, + _Timer_server_Get_ticks, + true + ); - while ( true ) { - _Timer_server_Get_watchdogs_that_fire_now( ts, &insert_chain, &fire_chain ); - - if ( !_Chain_Is_empty( &fire_chain ) ) { - /* - * Fire the watchdogs. - */ - while ( true ) { - Watchdog_Control *watchdog; - ISR_Level level; - - /* - * It is essential that interrupts are disable here since an interrupt - * service routine may remove a watchdog from the chain. - */ - _ISR_Disable( level ); - watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &fire_chain ); - if ( watchdog != NULL ) { - watchdog->state = WATCHDOG_INACTIVE; - _ISR_Enable( level ); - } else { - _ISR_Enable( level ); - - break; - } + _Timer_server_Tickle( + &ts->TOD_watchdogs, + &_Watchdog_Seconds_header, + _Timer_server_Get_seconds, + false + ); - _Timer_server_SMP_lock_release(); + (void) rtems_event_system_receive( + RTEMS_EVENT_SYSTEM_TIMER_SERVER, + RTEMS_EVENT_ALL | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + } +} - /* - * The timer server may block here and wait for resources or time. - * The system watchdogs are inactive and will remain inactive since - * the active flag of the timer server is true. - */ - (*watchdog->routine)( watchdog->id, watchdog->user_data ); +static void _Timer_server_Wakeup( + Objects_Id id, + void *arg +) +{ + Timer_server_Control *ts = arg; - _Timer_server_SMP_lock_aquire(); - } - } else { - ts->active = false; + _Timer_server_Update_current_snapshot( + &ts->Interval_watchdogs, + _Timer_server_Get_ticks + ); - /* - * Block until there is something to do. - */ -#if !defined( RTEMS_SMP ) - _Thread_Disable_dispatch(); -#endif - _Thread_Set_state( ts->thread, STATES_DELAYING ); - _Timer_server_Reset_interval_system_watchdog( ts ); - _Timer_server_Reset_tod_system_watchdog( ts ); -#if !defined( RTEMS_SMP ) - _Thread_Enable_dispatch(); -#endif + _Timer_server_Update_current_snapshot( + &ts->TOD_watchdogs, + _Timer_server_Get_seconds + ); - _Timer_server_SMP_lock_release(); - _Timer_server_SMP_lock_aquire(); + (void) rtems_event_system_send( id, RTEMS_EVENT_SYSTEM_TIMER_SERVER ); +} - ts->active = true; +static void _Timer_server_Initialize_watchdogs( + Timer_server_Control *ts, + rtems_id id, + Timer_server_Watchdogs *watchdogs, + Watchdog_Interval (*get_ticks)( void ) +) +{ + Watchdog_Interval now; - /* - * Maybe an interrupt did reset the system timers, so we have to stop - * them here. Since we are active now, there will be no more resets - * until we are inactive again. - */ - _Timer_server_Stop_interval_system_watchdog( ts ); - _Timer_server_Stop_tod_system_watchdog( ts ); - } - } + now = (*get_ticks)(); + watchdogs->last_snapshot = now; + watchdogs->current_snapshot = now; + + _Watchdog_Header_initialize( &watchdogs->Header ); + _Watchdog_Initialize( + &watchdogs->System_watchdog, + _Timer_server_Wakeup, + id, + ts + ); } /** @@ -542,36 +390,18 @@ rtems_status_code rtems_timer_initiate_server( * Timer Server so we do not have to have a critical section. */ - /* - * We work with the TCB pointer, not the ID, so we need to convert - * to a TCB pointer from here out. - */ - ts->thread = (Thread_Control *)_Objects_Get_local_object( - &_RTEMS_tasks_Information, - _Objects_Get_index(id) + _Timer_server_Initialize_watchdogs( + ts, + id, + &ts->Interval_watchdogs, + _Timer_server_Get_ticks ); - /* - * Initialize the timer lists that the server will manage. - */ - _Watchdog_Header_initialize( &ts->Interval_watchdogs.Header ); - _Watchdog_Header_initialize( &ts->TOD_watchdogs.Header ); - - /* - * Initialize the timers that will be used to control when the - * Timer Server wakes up and services the task-based timers. - */ - _Watchdog_Initialize( - &ts->Interval_watchdogs.System_watchdog, - _Thread_Delay_ended, - 0, - ts->thread - ); - _Watchdog_Initialize( - &ts->TOD_watchdogs.System_watchdog, - _Thread_Delay_ended, - 0, - ts->thread + _Timer_server_Initialize_watchdogs( + ts, + id, + &ts->TOD_watchdogs, + _Timer_server_Get_seconds ); /* @@ -581,12 +411,6 @@ rtems_status_code rtems_timer_initiate_server( ts->cancel = _Timer_server_Cancel_method; ts->schedule_operation = _Timer_server_Schedule_operation_method; - ts->Interval_watchdogs.last_snapshot = _Watchdog_Ticks_since_boot; - ts->TOD_watchdogs.last_snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); - - ts->insert_chain = NULL; - ts->active = false; - /* * The default timer server is now available. */ diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index af7da2ac53..3eb2caa902 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -324,7 +324,7 @@ libscore_a_SOURCES += src/coretod.c src/coretodset.c src/coretodget.c \ ## WATCHDOG_C_FILES libscore_a_SOURCES += src/watchdog.c src/watchdogadjust.c \ - src/watchdogadjusttochain.c src/watchdoginsert.c src/watchdogremove.c + src/watchdoginsert.c src/watchdogremove.c libscore_a_SOURCES += src/watchdogtickssinceboot.c ## USEREXT_C_FILES diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index dfe50e6d3a..6804bf24d4 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -164,6 +164,22 @@ void _Watchdog_Adjust_backward( Watchdog_Interval units ); +/** + * @brief Adjusts the watchdogs in backward direction in a locked context. + * + * The caller must be the owner of the watchdog lock and will be the owner + * after the call. + * + * @param[in] header The watchdog header. + * @param[in] units The units of ticks to adjust. + * + * @see _Watchdog_Adjust_forward(). + */ +void _Watchdog_Adjust_backward_locked( + Watchdog_Header *header, + Watchdog_Interval units +); + /** * @brief Adjusts the header watchdog chain in the forward direction for units * ticks. @@ -179,24 +195,22 @@ void _Watchdog_Adjust_forward( ); /** - * @brief Adjusts the @a header watchdog chain in the forward - * @a direction for @a units_arg ticks. + * @brief Adjusts the watchdogs in forward direction in a locked context. * - * This routine adjusts the @a header watchdog chain in the forward - * @a direction for @a units_arg ticks. + * The caller must be the owner of the watchdog lock and will be the owner + * after the call. This function may release and acquire the watchdog lock + * internally. * - * @param[in] header is the watchdog chain to adjust - * @param[in] units_arg is the number of units to adjust @a header - * @param[in] to_fire is a pointer to an initialized Chain_Control to which - * all watchdog instances that are to be fired will be placed. + * @param[in] header The watchdog header. + * @param[in] units The units of ticks to adjust. + * @param[in] lock_context The lock context. * - * @note This always adjusts forward. + * @see _Watchdog_Adjust_forward(). */ -void _Watchdog_Adjust_to_chain( +void _Watchdog_Adjust_forward_locked( Watchdog_Header *header, - Watchdog_Interval units_arg, - Chain_Control *to_fire - + Watchdog_Interval units, + ISR_lock_Context *lock_context ); /** @@ -215,6 +229,25 @@ void _Watchdog_Insert ( Watchdog_Control *the_watchdog ); +/** + * @brief Inserts the watchdog in a locked context. + * + * The caller must be the owner of the watchdog lock and will be the owner + * after the call. This function may release and acquire the watchdog lock + * internally. + * + * @param[in] header The watchdog header. + * @param[in] the_watchdog The watchdog. + * @param[in] lock_context The lock context. + * + * @see _Watchdog_Insert(). + */ +void _Watchdog_Insert_locked( + Watchdog_Header *header, + Watchdog_Control *the_watchdog, + ISR_lock_Context *lock_context +); + /** * @brief This routine is invoked at appropriate intervals to update * the @a header watchdog chain. diff --git a/cpukit/score/src/watchdogadjust.c b/cpukit/score/src/watchdogadjust.c index 04fc1a55a7..32b5f7990e 100644 --- a/cpukit/score/src/watchdogadjust.c +++ b/cpukit/score/src/watchdogadjust.c @@ -19,26 +19,18 @@ #endif #include -#include -#include -void _Watchdog_Adjust_backward( +void _Watchdog_Adjust_backward_locked( Watchdog_Header *header, Watchdog_Interval units ) { - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - if ( !_Watchdog_Is_empty( header ) ) { _Watchdog_First( header )->delta_interval += units; } - - _Watchdog_Release( header, &lock_context ); } -void _Watchdog_Adjust_forward( +void _Watchdog_Adjust_backward( Watchdog_Header *header, Watchdog_Interval units ) @@ -46,7 +38,16 @@ void _Watchdog_Adjust_forward( 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 ); @@ -57,13 +58,23 @@ void _Watchdog_Adjust_forward( units -= first->delta_interval; first->delta_interval = 1; - _Watchdog_Release( header, &lock_context ); + _Watchdog_Release( header, lock_context ); _Watchdog_Tickle( header ); - _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Acquire( header, lock_context ); } } +} +void _Watchdog_Adjust_forward( + Watchdog_Header *header, + Watchdog_Interval units +) +{ + ISR_lock_Context lock_context; + + _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Adjust_forward_locked( header, units, &lock_context ); _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdogadjusttochain.c b/cpukit/score/src/watchdogadjusttochain.c deleted file mode 100644 index b3063e4109..0000000000 --- a/cpukit/score/src/watchdogadjusttochain.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file - * - * @brief Watchdog Adjust to Chain - * @ingroup ScoreWatchdog - */ - -/* - * COPYRIGHT (c) 1989-2009. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -void _Watchdog_Adjust_to_chain( - Watchdog_Header *header, - Watchdog_Interval units_arg, - Chain_Control *to_fire - -) -{ - Watchdog_Interval units = units_arg; - ISR_lock_Context lock_context; - Watchdog_Control *first; - - _Watchdog_Acquire( header, &lock_context ); - - while ( 1 ) { - if ( _Watchdog_Is_empty( header ) ) { - break; - } - first = _Watchdog_First( header ); - - /* - * If it is longer than "units" until the first element on the chain - * fires, then bump it and quit. - */ - if ( units < first->delta_interval ) { - first->delta_interval -= units; - break; - } - - /* - * The first set happens in less than units, so take all of them - * off the chain and adjust units to reflect this. - */ - units -= first->delta_interval; - first->delta_interval = 0; - - while ( 1 ) { - _Chain_Extract_unprotected( &first->Node ); - _Chain_Append_unprotected( to_fire, &first->Node ); - - _Watchdog_Flash( header, &lock_context ); - - if ( _Watchdog_Is_empty( header ) ) - break; - first = _Watchdog_First( header ); - if ( first->delta_interval != 0 ) - break; - } - } - - _Watchdog_Release( header, &lock_context ); -} - diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c index 6d2df8222f..6b81c7b872 100644 --- a/cpukit/score/src/watchdoginsert.c +++ b/cpukit/score/src/watchdoginsert.c @@ -47,15 +47,12 @@ static void _Watchdog_Insert_fixup( } } -void _Watchdog_Insert( +void _Watchdog_Insert_locked( Watchdog_Header *header, - Watchdog_Control *the_watchdog + Watchdog_Control *the_watchdog, + ISR_lock_Context *lock_context ) { - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - if ( the_watchdog->state == WATCHDOG_INACTIVE ) { Watchdog_Iterator iterator; Chain_Node *current; @@ -86,7 +83,7 @@ void _Watchdog_Insert( iterator.delta_interval = delta - delta_next; iterator.current = next; - _Watchdog_Flash( header, &lock_context ); + _Watchdog_Flash( header, lock_context ); if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { goto abort_insert; @@ -105,6 +102,16 @@ abort_insert: _Chain_Extract_unprotected( &iterator.Node ); } +} +void _Watchdog_Insert( + Watchdog_Header *header, + Watchdog_Control *the_watchdog +) +{ + ISR_lock_Context lock_context; + + _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Insert_locked( header, the_watchdog, &lock_context ); _Watchdog_Release( header, &lock_context ); } diff --git a/testsuites/sptests/spintrcritical17/init.c b/testsuites/sptests/spintrcritical17/init.c index 9dde48a06b..238493e71a 100644 --- a/testsuites/sptests/spintrcritical17/init.c +++ b/testsuites/sptests/spintrcritical17/init.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2009 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * + * Copyright (c) 2009-2014 embedded brains GmbH. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -22,141 +23,91 @@ const char rtems_test_name[] = "SPINTRCRITICAL 17"; -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); - -#define TIMER_COUNT 4 - -#define TIMER_TRIGGER 0 -#define TIMER_RESET 1 -#define TIMER_NEVER_INTERVAL 2 -#define TIMER_NEVER_TOD 3 - -static rtems_id timer [TIMER_COUNT]; +typedef struct { + rtems_id timer1; + rtems_id timer2; + bool done; +} test_context; -static rtems_time_of_day tod; - -static volatile bool case_hit; - -static void never_callback(rtems_id timer, void *arg) -{ - rtems_test_assert(false); -} +static test_context ctx_instance; -static void reset_tod_timer(void) +static void never(rtems_id timer_id, void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_timer_server_fire_when( - timer [TIMER_NEVER_TOD], - &tod, - never_callback, - NULL - ); - directive_failed_with_level(sc, "rtems_timer_server_fire_after", -1); + rtems_test_assert(0); } -static void reset_callback(rtems_id timer_id, void *arg) +static void fire(rtems_id timer_id, void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_timer_reset(timer [TIMER_RESET]); - directive_failed_with_level(sc, "rtems_timer_reset", -1); - - sc = rtems_timer_reset(timer [TIMER_NEVER_INTERVAL]); - directive_failed_with_level(sc, "rtems_timer_reset", -1); - - reset_tod_timer(); - - if (!case_hit) { - case_hit = _Timer_server->insert_chain != NULL; + /* 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 void trigger_callback(rtems_id timer_id, void *arg) +static bool test_body(void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; + test_context *ctx = arg; + rtems_status_code sc; - if (case_hit) { - TEST_END(); + sc = rtems_timer_reset(ctx->timer1); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - rtems_test_exit(0); - } else if (interrupt_critical_section_test_support_delay()) { - puts("test case not hit, give up"); - - rtems_test_exit(0); - } - - sc = rtems_timer_reset(timer [TIMER_TRIGGER]); - directive_failed(sc, "rtems_timer_reset"); + return ctx->done; } -rtems_task Init( rtems_task_argument ignored ) +static void Init(rtems_task_argument ignored) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - size_t i = 0; + test_context *ctx = &ctx_instance; + rtems_status_code sc; TEST_BEGIN(); - build_time(&tod, 4, 12, 2009, 9, 34, 11, 0); - sc = rtems_clock_set(&tod); - directive_failed(sc, "rtems_clock_set"); - - ++tod.year; + sc = rtems_timer_create( + rtems_build_name('T', 'I', 'M', '1'), + &ctx->timer1 + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - for (i = 0; i < TIMER_COUNT; ++i) { - sc = rtems_timer_create( - rtems_build_name('T', 'I', 'M', '0' + i), - &timer [i] - ); - directive_failed(sc, "rtems_timer_create"); - } + 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 ); - directive_failed(sc, "rtems_timer_initiate_server"); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - sc = rtems_timer_server_fire_after( - timer [TIMER_NEVER_INTERVAL], - 2, - never_callback, - NULL - ); - directive_failed(sc, "rtems_timer_server_fire_after"); - - reset_tod_timer(); - - sc = rtems_timer_fire_after( - timer [TIMER_RESET], - 1, - reset_callback, - NULL - ); - directive_failed(sc, "rtems_timer_fire_after"); - - sc = rtems_timer_server_fire_after( - timer [TIMER_TRIGGER], - 1, - trigger_callback, - NULL - ); - directive_failed(sc, "rtems_timer_server_fire_after"); + sc = rtems_timer_server_fire_after(ctx->timer1, 1000, never, NULL); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - interrupt_critical_section_test_support_initialize(NULL); + interrupt_critical_section_test(test_body, ctx, fire); + rtems_test_assert(ctx->done); - rtems_task_delete(RTEMS_SELF); + TEST_END(); + rtems_test_exit(0); } #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER -#define CONFIGURE_MICROSECONDS_PER_TICK 2000 +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 #define CONFIGURE_MAXIMUM_TASKS 2 -#define CONFIGURE_MAXIMUM_TIMERS 4 +#define CONFIGURE_MAXIMUM_TIMERS 3 +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION diff --git a/testsuites/sptests/spintrcritical17/spintrcritical17.doc b/testsuites/sptests/spintrcritical17/spintrcritical17.doc index 3be8e60c52..809a9669d6 100644 --- a/testsuites/sptests/spintrcritical17/spintrcritical17.doc +++ b/testsuites/sptests/spintrcritical17/spintrcritical17.doc @@ -1,4 +1,4 @@ -# Copyright (c) 2009 embedded brains GmbH. +# 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 @@ -11,9 +11,7 @@ test set name: spintrcritical17 directives: - _Timer_server_Get_watchdogs_that_fire_now - _Timer_server_Schedule_operation_method - _Timer_server_Process_insertions + _Timer_server_Update_system_watchdog concepts: -- cgit v1.2.3 From d5a9c808f06e5b458c583caa4c2df6de8cc89124 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 08:56:14 +0200 Subject: rtems: Use once mutex for timer server init --- cpukit/rtems/src/timerserver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index db38f48484..047fd0978e 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -29,6 +29,7 @@ #include #include #include +#include #include static Timer_server_Control _Timer_server_Default; @@ -346,10 +347,10 @@ rtems_status_code rtems_timer_initiate_server( /* * Just to make sure this is only called once. */ - _Thread_Disable_dispatch(); + _Once_Lock(); tmpInitialized = initialized; initialized = true; - _Thread_Enable_dispatch(); + _Once_Unlock(); if ( tmpInitialized ) return RTEMS_INCORRECT_STATE; -- cgit v1.2.3 From 5f7f469a96bf8ffeab37f782062d13344e375b4a Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 09:22:26 +0200 Subject: libcsupport: Avoid Giant lock in _times() --- cpukit/libcsupport/src/__times.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cpukit/libcsupport/src/__times.c b/cpukit/libcsupport/src/__times.c index 5a1f9eba4d..895ee6b658 100644 --- a/cpukit/libcsupport/src/__times.c +++ b/cpukit/libcsupport/src/__times.c @@ -66,9 +66,10 @@ clock_t _times( #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ { - Timestamp_Control per_tick; - uint32_t ticks_of_executing; - uint32_t fractional_ticks; + Timestamp_Control per_tick; + uint32_t ticks_of_executing; + uint32_t fractional_ticks; + Per_CPU_Control *cpu_self; _Timestamp_Set( &per_tick, @@ -78,7 +79,7 @@ clock_t _times( TOD_NANOSECONDS_PER_SECOND) ); - _Thread_Disable_dispatch(); + cpu_self = _Thread_Dispatch_disable(); executing = _Thread_Executing; _Thread_Update_cpu_time_used( executing, @@ -90,7 +91,7 @@ clock_t _times( &ticks_of_executing, &fractional_ticks ); - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); ptms->tms_utime = ticks_of_executing * us_per_tick; } #else -- cgit v1.2.3 From c07c85f4f2d978224c90f1af5206e469da538599 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 09:24:10 +0200 Subject: Filesystem: Use lock for deferred release --- cpukit/libcsupport/src/sup_fs_location.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cpukit/libcsupport/src/sup_fs_location.c b/cpukit/libcsupport/src/sup_fs_location.c index 545dfe185f..ddda4d15eb 100644 --- a/cpukit/libcsupport/src/sup_fs_location.c +++ b/cpukit/libcsupport/src/sup_fs_location.c @@ -6,10 +6,10 @@ */ /* - * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * Copyright (c) 2012-2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH - * Obere Lagerstr. 30 + * Dornierstr. 4 * 82178 Puchheim * Germany * @@ -31,6 +31,12 @@ rtems_interrupt_lock rtems_filesystem_mt_entry_lock_control = RTEMS_INTERRUPT_LOCK_INITIALIZER("mount table entry"); +RTEMS_INTERRUPT_LOCK_DEFINE( + static, + deferred_release_lock, + "Filesystem Deferred Release" +) + static rtems_filesystem_global_location_t *deferred_released_global_locations; rtems_filesystem_location_info_t *rtems_filesystem_location_copy( @@ -134,9 +140,10 @@ static void deferred_release(void) rtems_filesystem_global_location_t *current = NULL; do { + rtems_interrupt_lock_context lock_context; int count = 0; - _Thread_Disable_dispatch(); + rtems_interrupt_lock_acquire(&deferred_release_lock, &lock_context); current = deferred_released_global_locations; if (current != NULL) { deferred_released_global_locations = current->deferred_released_next; @@ -144,7 +151,7 @@ static void deferred_release(void) current->deferred_released_next = NULL; current->deferred_released_count = 0; } - _Thread_Enable_dispatch(); + rtems_interrupt_lock_release(&deferred_release_lock, &lock_context); if (current != NULL) { release_with_count(current, count); @@ -182,6 +189,10 @@ void rtems_filesystem_global_location_release( if (_Thread_Dispatch_is_enabled()) { release_with_count(global_loc, 1); } else { + rtems_interrupt_lock_context lock_context; + + rtems_interrupt_lock_acquire(&deferred_release_lock, &lock_context); + if (global_loc->deferred_released_count == 0) { rtems_filesystem_global_location_t *head = deferred_released_global_locations; @@ -192,6 +203,8 @@ void rtems_filesystem_global_location_release( } else { ++global_loc->deferred_released_count; } + + rtems_interrupt_lock_release(&deferred_release_lock, &lock_context); } } -- cgit v1.2.3 From 2b0bbc4a654ecea922abc58b00e6bb8763aa4519 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 09:29:38 +0200 Subject: libcsupport: Avoid Giant lock in rtems_verror() --- cpukit/libcsupport/src/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpukit/libcsupport/src/error.c b/cpukit/libcsupport/src/error.c index 81ddae251a..44cc1ee688 100644 --- a/cpukit/libcsupport/src/error.c +++ b/cpukit/libcsupport/src/error.c @@ -36,7 +36,7 @@ int rtems_verror( if (error_flag & RTEMS_ERROR_PANIC) { if (rtems_panic_in_progress++) - _Thread_Disable_dispatch(); /* disable task switches */ + _Thread_Dispatch_disable(); /* disable task switches */ /* don't aggravate things */ if (rtems_panic_in_progress > 2) -- cgit v1.2.3 From 4a3c920d307f9da19a4215f2496e8ddd9bddce15 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 09:30:21 +0200 Subject: libcsupport: Fix umask() locking Delete comment related to an obsolete implementation of rtems_libio_set_private_env(). --- cpukit/libcsupport/src/umask.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cpukit/libcsupport/src/umask.c b/cpukit/libcsupport/src/umask.c index 678cac8c50..fba2405e4a 100644 --- a/cpukit/libcsupport/src/umask.c +++ b/cpukit/libcsupport/src/umask.c @@ -21,7 +21,6 @@ #include #include -#include /** * POSIX 1003.1b 5.3.3 - Set File Creation Mask @@ -30,14 +29,10 @@ mode_t umask( mode_t cmask ) { mode_t old_mask; - /* - * We must use the same protection mechanism as in - * rtems_libio_set_private_env(). - */ - _Thread_Disable_dispatch(); + rtems_libio_lock(); old_mask = rtems_filesystem_umask; rtems_filesystem_umask = cmask & (S_IRWXU | S_IRWXG | S_IRWXO); - _Thread_Enable_dispatch(); + rtems_libio_unlock(); return old_mask; } -- cgit v1.2.3 From 776a50c47a1751bf5c5957eab446d33fd50ebeae Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 09:32:00 +0200 Subject: Filesystem: Thread life protection for env changes --- cpukit/libcsupport/src/privateenv.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cpukit/libcsupport/src/privateenv.c b/cpukit/libcsupport/src/privateenv.c index 57177453c4..29821e4045 100644 --- a/cpukit/libcsupport/src/privateenv.c +++ b/cpukit/libcsupport/src/privateenv.c @@ -23,7 +23,7 @@ #include #include -#include +#include /** * Instantiate a private user environment for the calling thread. @@ -50,13 +50,6 @@ void rtems_libio_free_user_env(void *arg) } } -static void free_user_env_protected(rtems_user_env_t *env) -{ - _Thread_Disable_dispatch(); - rtems_libio_free_user_env(env); - _Thread_Enable_dispatch(); -} - rtems_status_code rtems_libio_set_private_env(void) { rtems_status_code sc = RTEMS_SUCCESSFUL; @@ -64,6 +57,7 @@ rtems_status_code rtems_libio_set_private_env(void) bool uses_global_env = old_env == &rtems_global_user_env; if (uses_global_env) { + bool life_protection = _Thread_Set_life_protection(true); rtems_user_env_t *new_env = calloc(1, sizeof(*new_env)); if (new_env != NULL) { @@ -83,7 +77,7 @@ rtems_status_code rtems_libio_set_private_env(void) ); if (eno == 0) { - free_user_env_protected(old_env); + rtems_libio_free_user_env(old_env); } else { sc = RTEMS_TOO_MANY; } @@ -97,6 +91,8 @@ rtems_status_code rtems_libio_set_private_env(void) } else { sc = RTEMS_NO_MEMORY; } + + _Thread_Set_life_protection(life_protection); } return sc; @@ -108,7 +104,11 @@ void rtems_libio_use_global_env(void) bool uses_private_env = env != &rtems_global_user_env; if (uses_private_env) { - free_user_env_protected(env); + bool life_protection = _Thread_Set_life_protection(true); + + rtems_libio_free_user_env(env); pthread_setspecific(rtems_current_user_env_key, NULL); + + _Thread_Set_life_protection(life_protection); } } -- cgit v1.2.3 From b7cff7feb0a0d41ec4876e5ac846bb6cf8254dce Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sun, 26 Apr 2015 15:22:20 +0200 Subject: score: Reduce thread wait states Merge THREAD_WAIT_STATE_SATISFIED, THREAD_WAIT_STATE_TIMEOUT, THREAD_WAIT_STATE_INTERRUPT_SATISFIED, and THREAD_WAIT_STATE_INTERRUPT_TIMEOUT into one state THREAD_WAIT_STATE_READY_AGAIN. This helps to write generic routines to block a thread. Update #2273. --- cpukit/rtems/src/eventsurrender.c | 4 ++-- cpukit/rtems/src/eventtimeout.c | 4 ++-- cpukit/score/include/rtems/score/thread.h | 7 ++----- cpukit/score/include/rtems/score/threadimpl.h | 25 ++++--------------------- testsuites/sptests/spintrcritical10/init.c | 6 +++--- 5 files changed, 13 insertions(+), 33 deletions(-) diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index e29d203f71..b740721e22 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -85,7 +85,7 @@ void _Event_Surrender( success = _Thread_Wait_flags_try_change_critical( the_thread, intend_to_block, - wait_class | THREAD_WAIT_STATE_INTERRUPT_SATISFIED + wait_class | THREAD_WAIT_STATE_READY_AGAIN ); if ( success ) { _Event_Satisfy( the_thread, event, pending_events, seized_events ); @@ -94,7 +94,7 @@ void _Event_Surrender( _Event_Satisfy( the_thread, event, pending_events, seized_events ); _Thread_Wait_flags_set( the_thread, - wait_class | THREAD_WAIT_STATE_SATISFIED + wait_class | THREAD_WAIT_STATE_READY_AGAIN ); unblock = true; } else { diff --git a/cpukit/rtems/src/eventtimeout.c b/cpukit/rtems/src/eventtimeout.c index 9c091748c0..5db118b183 100644 --- a/cpukit/rtems/src/eventtimeout.c +++ b/cpukit/rtems/src/eventtimeout.c @@ -45,7 +45,7 @@ void _Event_Timeout( success = _Thread_Wait_flags_try_change_critical( the_thread, intend_to_block, - wait_class | THREAD_WAIT_STATE_INTERRUPT_TIMEOUT + wait_class | THREAD_WAIT_STATE_READY_AGAIN ); if ( success ) { @@ -55,7 +55,7 @@ void _Event_Timeout( the_thread->Wait.return_code = RTEMS_TIMEOUT; _Thread_Wait_flags_set( the_thread, - wait_class | THREAD_WAIT_STATE_TIMEOUT + wait_class | THREAD_WAIT_STATE_READY_AGAIN ); unblock = true; } else { diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index 72e011ccff..112bd22e63 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -324,11 +324,8 @@ typedef union { * * The mutually exclusive wait state flags are * - @ref THREAD_WAIT_STATE_INTEND_TO_BLOCK, - * - @ref THREAD_WAIT_STATE_BLOCKED, - * - @ref THREAD_WAIT_STATE_SATISFIED, - * - @ref THREAD_WAIT_STATE_TIMEOUT, - * - @ref THREAD_WAIT_STATE_INTERRUPT_SATISFIED, and - * - @ref THREAD_WAIT_STATE_INTERRUPT_TIMEOUT, + * - @ref THREAD_WAIT_STATE_BLOCKED, and + * - @ref THREAD_WAIT_STATE_READY_AGAIN. */ typedef unsigned int Thread_Wait_flags; diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 84c9ac316f..3577a7493b 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -1138,28 +1138,11 @@ RTEMS_INLINE_ROUTINE void _Thread_Priority_restore_default_change_handler( #define THREAD_WAIT_STATE_BLOCKED 0x2U /** - * @brief Indicates that the thread progress condition is satisfied and it is - * ready to resume execution. - */ -#define THREAD_WAIT_STATE_SATISFIED 0x4U - -/** - * @brief Indicates that a timeout occurred and the thread is ready to resume - * execution. - */ -#define THREAD_WAIT_STATE_TIMEOUT 0x8U - -/** - * @brief Indicates that the thread progress condition was satisfied during the - * blocking operation and it is ready to resume execution. - */ -#define THREAD_WAIT_STATE_INTERRUPT_SATISFIED 0x10U - -/** - * @brief Indicates that a timeout occurred during the blocking operation and - * the thread is ready to resume execution. + * @brief Indicates that a condition to end the thread wait occurred. + * + * This could be a timeout, a signal, an event or a resource availability. */ -#define THREAD_WAIT_STATE_INTERRUPT_TIMEOUT 0x20U +#define THREAD_WAIT_STATE_READY_AGAIN 0x4U /** * @brief Mask to get the thread wait class flags. diff --git a/testsuites/sptests/spintrcritical10/init.c b/testsuites/sptests/spintrcritical10/init.c index 441b161b5b..e9f813d521 100644 --- a/testsuites/sptests/spintrcritical10/init.c +++ b/testsuites/sptests/spintrcritical10/init.c @@ -88,7 +88,7 @@ static void any_satisfy_before_timeout(rtems_id timer, void *arg) if (ctx->hit) { rtems_test_assert( _Thread_Wait_flags_get(thread) - == (THREAD_WAIT_CLASS_EVENT | THREAD_WAIT_STATE_INTERRUPT_SATISFIED) + == (THREAD_WAIT_CLASS_EVENT | THREAD_WAIT_STATE_READY_AGAIN) ); } @@ -185,7 +185,7 @@ static void all_satisfy_before_timeout(rtems_id timer, void *arg) if (ctx->hit) { rtems_test_assert( _Thread_Wait_flags_get(thread) - == (THREAD_WAIT_CLASS_EVENT | THREAD_WAIT_STATE_INTERRUPT_SATISFIED) + == (THREAD_WAIT_CLASS_EVENT | THREAD_WAIT_STATE_READY_AGAIN) ); } @@ -269,7 +269,7 @@ static void timeout_before_satisfied(rtems_id timer, void *arg) if (ctx->hit) { rtems_test_assert( _Thread_Wait_flags_get(thread) - == (THREAD_WAIT_CLASS_EVENT | THREAD_WAIT_STATE_INTERRUPT_TIMEOUT) + == (THREAD_WAIT_CLASS_EVENT | THREAD_WAIT_STATE_READY_AGAIN) ); } -- cgit v1.2.3 From 08fe84b5d7072b7809581b1a25954a3b221497a5 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 22 Apr 2015 10:06:05 +0200 Subject: score: Generalize _Event_Timeout() Add a thread wait timeout code. Replace _Event_Timeout() with a general purpose _Thread_Timeout() watchdog handler. Update #2273. --- cpukit/rtems/Makefile.am | 1 - cpukit/rtems/src/eventseize.c | 8 ++- cpukit/rtems/src/eventtimeout.c | 70 ------------------------- cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/thread.h | 5 ++ cpukit/score/include/rtems/score/threadimpl.h | 22 ++++++++ cpukit/score/src/threadtimeout.c | 74 +++++++++++++++++++++++++++ testsuites/sptests/spintrcritical10/init.c | 6 +-- 8 files changed, 112 insertions(+), 75 deletions(-) delete mode 100644 cpukit/rtems/src/eventtimeout.c create mode 100644 cpukit/score/src/threadtimeout.c diff --git a/cpukit/rtems/Makefile.am b/cpukit/rtems/Makefile.am index 5e6f2eafa0..084b39f8b3 100644 --- a/cpukit/rtems/Makefile.am +++ b/cpukit/rtems/Makefile.am @@ -210,7 +210,6 @@ librtems_a_SOURCES += src/eventreceive.c librtems_a_SOURCES += src/eventseize.c librtems_a_SOURCES += src/eventsend.c librtems_a_SOURCES += src/eventsurrender.c -librtems_a_SOURCES += src/eventtimeout.c librtems_a_SOURCES += src/systemeventsend.c librtems_a_SOURCES += src/systemeventreceive.c diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index 36b1964820..6611a8d6f6 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -89,7 +89,13 @@ void _Event_Seize( _Giant_Acquire( cpu_self ); if ( ticks ) { - _Watchdog_Initialize( &executing->Timer, _Event_Timeout, 0, executing ); + _Thread_Wait_set_timeout_code( executing, RTEMS_TIMEOUT ); + _Watchdog_Initialize( + &executing->Timer, + _Thread_Timeout, + 0, + executing + ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); } diff --git a/cpukit/rtems/src/eventtimeout.c b/cpukit/rtems/src/eventtimeout.c deleted file mode 100644 index 5db118b183..0000000000 --- a/cpukit/rtems/src/eventtimeout.c +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file - * - * @brief Timeout Event - * @ingroup ClassicEvent - */ - -/* - * COPYRIGHT (c) 1989-2008. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H - #include "config.h" -#endif - -#include -#include - -void _Event_Timeout( - Objects_Id id, - void *arg -) -{ - Thread_Control *the_thread; - ISR_lock_Context lock_context; - Thread_Wait_flags wait_flags; - Thread_Wait_flags wait_class; - Thread_Wait_flags intend_to_block; - Thread_Wait_flags blocked; - bool success; - bool unblock; - - the_thread = arg; - _Thread_Lock_acquire_default( the_thread, &lock_context ); - - wait_flags = _Thread_Wait_flags_get( the_thread ); - wait_class = wait_flags & THREAD_WAIT_CLASS_MASK; - intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK; - blocked = wait_class | THREAD_WAIT_STATE_BLOCKED; - success = _Thread_Wait_flags_try_change_critical( - the_thread, - intend_to_block, - wait_class | THREAD_WAIT_STATE_READY_AGAIN - ); - - if ( success ) { - the_thread->Wait.return_code = RTEMS_TIMEOUT; - unblock = false; - } else if ( _Thread_Wait_flags_get( the_thread ) == blocked ) { - the_thread->Wait.return_code = RTEMS_TIMEOUT; - _Thread_Wait_flags_set( - the_thread, - wait_class | THREAD_WAIT_STATE_READY_AGAIN - ); - unblock = true; - } else { - unblock = false; - } - - _Thread_Lock_release_default( the_thread, &lock_context ); - - if ( unblock ) { - _Thread_Unblock( the_thread ); - } -} diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 3eb2caa902..35470972af 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -290,6 +290,7 @@ libscore_a_SOURCES += src/thread.c src/threadchangepriority.c \ src/threadstackallocate.c src/threadstackfree.c src/threadstart.c \ src/threadstartmultitasking.c src/iterateoverthreads.c libscore_a_SOURCES += src/threadglobalconstruction.c +libscore_a_SOURCES += src/threadtimeout.c libscore_a_SOURCES += src/threadyield.c if HAS_SMP diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index 112bd22e63..1a73fdaa8a 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -354,6 +354,11 @@ typedef struct { */ uint32_t return_code; + /** + * @brief Code to set the timeout return code in _Thread_Timeout(). + */ + uint32_t timeout_code; + /** This field points to the thread queue on which this thread is blocked. */ Thread_queue_Control *queue; diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 3577a7493b..c266a9cce3 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -1257,6 +1257,28 @@ RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change( return success; } +/** + * @brief Sets the thread wait timeout code. + * + * @param[in] the_thread The thread. + * @param[in] timeout_code The new thread wait timeout code. + */ +RTEMS_INLINE_ROUTINE void _Thread_Wait_set_timeout_code( + Thread_Control *the_thread, + uint32_t timeout_code +) +{ + the_thread->Wait.timeout_code = timeout_code; +} + +/** + * @brief General purpose thread wait timeout. + * + * @param[in] id Unused. + * @param[in] arg The thread. + */ +void _Thread_Timeout( Objects_Id id, void *arg ); + RTEMS_INLINE_ROUTINE void _Thread_Debug_set_real_processor( Thread_Control *the_thread, Per_CPU_Control *cpu diff --git a/cpukit/score/src/threadtimeout.c b/cpukit/score/src/threadtimeout.c new file mode 100644 index 0000000000..b6ce2d7362 --- /dev/null +++ b/cpukit/score/src/threadtimeout.c @@ -0,0 +1,74 @@ +/** + * @file + * + * @brief Thread Wait Timeout + * + * @ingroup ScoreThread + */ + +/* + * COPYRIGHT (c) 1989-2008. + * 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 + +static void _Thread_Do_timeout( Thread_Control *the_thread ) +{ + the_thread->Wait.return_code = the_thread->Wait.timeout_code; + _Thread_Lock_restore_default( the_thread ); +} + +void _Thread_Timeout( Objects_Id id, void *arg ) +{ + Thread_Control *the_thread; + ISR_lock_Control *thread_lock; + ISR_lock_Context lock_context; + Thread_Wait_flags wait_flags; + Thread_Wait_flags wait_class; + Thread_Wait_flags intend_to_block; + Thread_Wait_flags blocked; + bool success; + bool unblock; + + the_thread = arg; + thread_lock = _Thread_Lock_acquire( the_thread, &lock_context ); + + wait_flags = _Thread_Wait_flags_get( the_thread ); + wait_class = wait_flags & THREAD_WAIT_CLASS_MASK; + intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK; + blocked = wait_class | THREAD_WAIT_STATE_BLOCKED; + success = _Thread_Wait_flags_try_change_critical( + the_thread, + intend_to_block, + wait_class | THREAD_WAIT_STATE_READY_AGAIN + ); + + if ( success ) { + _Thread_Do_timeout( the_thread ); + unblock = false; + } else if ( _Thread_Wait_flags_get( the_thread ) == blocked ) { + _Thread_Wait_flags_set( + the_thread, + wait_class | THREAD_WAIT_STATE_READY_AGAIN + ); + _Thread_Do_timeout( the_thread ); + unblock = true; + } else { + unblock = false; + } + + _Thread_Lock_release( thread_lock, &lock_context ); + + if ( unblock ) { + _Thread_Unblock( the_thread ); + } +} diff --git a/testsuites/sptests/spintrcritical10/init.c b/testsuites/sptests/spintrcritical10/init.c index e9f813d521..e4a2a940a6 100644 --- a/testsuites/sptests/spintrcritical10/init.c +++ b/testsuites/sptests/spintrcritical10/init.c @@ -78,7 +78,7 @@ static void any_satisfy_before_timeout(rtems_id timer, void *arg) ); rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL); - _Event_Timeout(0, thread); + _Thread_Timeout(0, thread); 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); - _Event_Timeout(0, thread); + _Thread_Timeout(0, thread); 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); - _Event_Timeout(0, thread); + _Thread_Timeout(0, thread); rtems_test_assert( *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF -- cgit v1.2.3 From 02c4c441a51b43b55608893efa4a80a62bb9d4d5 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 23 Apr 2015 10:01:22 +0200 Subject: score: Add Thread_queue_Control::Lock Move the complete thread queue enqueue procedure into _Thread_queue_Enqueue_critical(). It is possible to use the thread queue lock to protect state of the object embedding the thread queue. This enables per object fine grained locking in the future. Delete _Thread_queue_Enter_critical_section(). Update #2273. --- cpukit/posix/include/rtems/posix/barrierimpl.h | 1 + cpukit/posix/include/rtems/posix/condimpl.h | 2 + cpukit/posix/include/rtems/posix/muteximpl.h | 1 + cpukit/posix/include/rtems/posix/psignalimpl.h | 8 +- cpukit/posix/include/rtems/posix/rwlockimpl.h | 1 + cpukit/posix/include/rtems/posix/semaphoreimpl.h | 1 + cpukit/posix/src/condwaitsupp.c | 2 - cpukit/posix/src/psignal.c | 2 - cpukit/posix/src/pthread.c | 2 + cpukit/posix/src/pthreadjoin.c | 1 - cpukit/posix/src/sigtimedwait.c | 8 +- cpukit/rtems/include/rtems/rtems/barrierimpl.h | 1 + cpukit/rtems/include/rtems/rtems/messageimpl.h | 1 + cpukit/rtems/include/rtems/rtems/regionimpl.h | 2 + cpukit/rtems/src/regioncreate.c | 18 ++-- cpukit/rtems/src/regiongetsegment.c | 3 - cpukit/rtems/src/semdelete.c | 2 + cpukit/score/include/rtems/score/corebarrierimpl.h | 8 ++ cpukit/score/include/rtems/score/coremuteximpl.h | 5 + cpukit/score/include/rtems/score/corerwlockimpl.h | 8 ++ cpukit/score/include/rtems/score/coresemimpl.h | 19 ++-- cpukit/score/include/rtems/score/threadq.h | 13 +++ cpukit/score/include/rtems/score/threadqimpl.h | 114 ++++++++++++++++----- cpukit/score/src/corebarrierwait.c | 16 ++- cpukit/score/src/coremsgclose.c | 1 + cpukit/score/src/coremsgseize.c | 16 ++- cpukit/score/src/coremsgsubmit.c | 6 -- cpukit/score/src/coremutexseize.c | 18 +++- cpukit/score/src/corerwlockobtainread.c | 20 ++-- cpukit/score/src/corerwlockobtainwrite.c | 22 ++-- cpukit/score/src/coresemseize.c | 18 ++-- cpukit/score/src/mpci.c | 2 - cpukit/score/src/threadq.c | 3 +- cpukit/score/src/threadqenqueue.c | 63 ++++++------ cpukit/score/src/threadqfirst.c | 22 ++-- 35 files changed, 261 insertions(+), 169 deletions(-) diff --git a/cpukit/posix/include/rtems/posix/barrierimpl.h b/cpukit/posix/include/rtems/posix/barrierimpl.h index 240abad45d..22be1c0d6e 100644 --- a/cpukit/posix/include/rtems/posix/barrierimpl.h +++ b/cpukit/posix/include/rtems/posix/barrierimpl.h @@ -80,6 +80,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Barrier_Free ( POSIX_Barrier_Control *the_barrier ) { + _CORE_barrier_Destroy( &the_barrier->Barrier ); _Objects_Free( &_POSIX_Barrier_Information, &the_barrier->Object ); } diff --git a/cpukit/posix/include/rtems/posix/condimpl.h b/cpukit/posix/include/rtems/posix/condimpl.h index 435127ee3c..7def0f852a 100644 --- a/cpukit/posix/include/rtems/posix/condimpl.h +++ b/cpukit/posix/include/rtems/posix/condimpl.h @@ -19,6 +19,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -72,6 +73,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Condition_variables_Free ( POSIX_Condition_variables_Control *the_condition_variable ) { + _Thread_queue_Destroy( &the_condition_variable->Wait_queue ); _Objects_Free( &_POSIX_Condition_variables_Information, &the_condition_variable->Object diff --git a/cpukit/posix/include/rtems/posix/muteximpl.h b/cpukit/posix/include/rtems/posix/muteximpl.h index 821961c0f4..f4c6c686aa 100644 --- a/cpukit/posix/include/rtems/posix/muteximpl.h +++ b/cpukit/posix/include/rtems/posix/muteximpl.h @@ -72,6 +72,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Mutex_Free( POSIX_Mutex_Control *the_mutex ) { + _CORE_mutex_Destroy( &the_mutex->Mutex ); _Objects_Free( &_POSIX_Mutex_Information, &the_mutex->Object ); } diff --git a/cpukit/posix/include/rtems/posix/psignalimpl.h b/cpukit/posix/include/rtems/posix/psignalimpl.h index 81561e2539..166705b37b 100644 --- a/cpukit/posix/include/rtems/posix/psignalimpl.h +++ b/cpukit/posix/include/rtems/posix/psignalimpl.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #define _States_Is_interruptible_signal( _states ) \ ( ((_states) & \ @@ -55,8 +55,6 @@ * Variables */ -extern ISR_lock_Control _POSIX_signals_Lock; - extern sigset_t _POSIX_signals_Pending; extern const struct sigaction _POSIX_signals_Default_vectors[ SIG_ARRAY_MAX ]; @@ -79,10 +77,10 @@ extern Chain_Control _POSIX_signals_Siginfo[ SIG_ARRAY_MAX ]; void _POSIX_signals_Manager_Initialization(void); #define _POSIX_signals_Acquire( lock_context ) \ - _ISR_lock_ISR_disable_and_acquire( &_POSIX_signals_Lock, lock_context ) + _Thread_queue_Acquire( &_POSIX_signals_Wait_queue, lock_context ) #define _POSIX_signals_Release( lock_context ) \ - _ISR_lock_Release_and_ISR_enable( &_POSIX_signals_Lock, lock_context ) + _Thread_queue_Release( &_POSIX_signals_Wait_queue, lock_context ) void _POSIX_signals_Action_handler( Thread_Control *executing, diff --git a/cpukit/posix/include/rtems/posix/rwlockimpl.h b/cpukit/posix/include/rtems/posix/rwlockimpl.h index 48e0a17366..46e33904dc 100644 --- a/cpukit/posix/include/rtems/posix/rwlockimpl.h +++ b/cpukit/posix/include/rtems/posix/rwlockimpl.h @@ -89,6 +89,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_RWLock_Free ( POSIX_RWLock_Control *the_RWLock ) { + _CORE_RWLock_Destroy( &the_RWLock->RWLock ); _Objects_Free( &_POSIX_RWLock_Information, &the_RWLock->Object ); } diff --git a/cpukit/posix/include/rtems/posix/semaphoreimpl.h b/cpukit/posix/include/rtems/posix/semaphoreimpl.h index df5e5238de..783289aa44 100644 --- a/cpukit/posix/include/rtems/posix/semaphoreimpl.h +++ b/cpukit/posix/include/rtems/posix/semaphoreimpl.h @@ -65,6 +65,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Semaphore_Free ( POSIX_Semaphore_Control *the_semaphore ) { + _CORE_semaphore_Destroy( &the_semaphore->Semaphore ); _Objects_Free( &_POSIX_Semaphore_Information, &the_semaphore->Object ); } diff --git a/cpukit/posix/src/condwaitsupp.c b/cpukit/posix/src/condwaitsupp.c index 1abdc426fc..8a9e23540c 100644 --- a/cpukit/posix/src/condwaitsupp.c +++ b/cpukit/posix/src/condwaitsupp.c @@ -74,10 +74,8 @@ int _POSIX_Condition_variables_Wait_support( if ( !already_timedout ) { the_cond->Mutex = *mutex; - _Thread_queue_Enter_critical_section( &the_cond->Wait_queue ); executing = _Thread_Executing; executing->Wait.return_code = 0; - executing->Wait.queue = &the_cond->Wait_queue; executing->Wait.id = *cond; _Thread_queue_Enqueue( diff --git a/cpukit/posix/src/psignal.c b/cpukit/posix/src/psignal.c index eec4d95fb5..543b558eac 100644 --- a/cpukit/posix/src/psignal.c +++ b/cpukit/posix/src/psignal.c @@ -45,8 +45,6 @@ RTEMS_STATIC_ASSERT( /*** PROCESS WIDE STUFF ****/ -ISR_lock_Control _POSIX_signals_Lock = ISR_LOCK_INITIALIZER("POSIX signals"); - sigset_t _POSIX_signals_Pending; void _POSIX_signals_Abnormal_termination_handler( diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index 97882bf4cb..2817891ac5 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -288,6 +288,8 @@ static void _POSIX_Threads_Terminate_extension( if ( api->schedpolicy == SCHED_SPORADIC ) _Watchdog_Remove_ticks( &api->Sporadic_timer ); + _Thread_queue_Destroy( &api->Join_List ); + _Thread_Enable_dispatch(); } diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c index e2b1664b0b..48fb7d58df 100644 --- a/cpukit/posix/src/pthreadjoin.c +++ b/cpukit/posix/src/pthreadjoin.c @@ -67,7 +67,6 @@ on_EINTR: _Thread_Clear_state( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); } else { executing->Wait.return_argument = &return_pointer; - _Thread_queue_Enter_critical_section( &api->Join_List ); _Thread_queue_Enqueue( &api->Join_List, executing, diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c index 8d86ba72a9..e988761453 100644 --- a/cpukit/posix/src/sigtimedwait.c +++ b/cpukit/posix/src/sigtimedwait.c @@ -152,17 +152,15 @@ int sigtimedwait( the_info->si_signo = -1; _Thread_Disable_dispatch(); - executing->Wait.queue = &_POSIX_signals_Wait_queue; executing->Wait.return_code = EINTR; executing->Wait.option = *set; executing->Wait.return_argument = the_info; - _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue ); - _POSIX_signals_Release( &lock_context ); - _Thread_queue_Enqueue( + _Thread_queue_Enqueue_critical( &_POSIX_signals_Wait_queue, executing, STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL, - interval + interval, + &lock_context ); _Thread_Enable_dispatch(); diff --git a/cpukit/rtems/include/rtems/rtems/barrierimpl.h b/cpukit/rtems/include/rtems/rtems/barrierimpl.h index 963ebd93da..e718028715 100644 --- a/cpukit/rtems/include/rtems/rtems/barrierimpl.h +++ b/cpukit/rtems/include/rtems/rtems/barrierimpl.h @@ -86,6 +86,7 @@ RTEMS_INLINE_ROUTINE void _Barrier_Free ( Barrier_Control *the_barrier ) { + _CORE_barrier_Destroy( &the_barrier->Barrier ); _Objects_Free( &_Barrier_Information, &the_barrier->Object ); } diff --git a/cpukit/rtems/include/rtems/rtems/messageimpl.h b/cpukit/rtems/include/rtems/rtems/messageimpl.h index e2bc88d0db..fa9e573892 100644 --- a/cpukit/rtems/include/rtems/rtems/messageimpl.h +++ b/cpukit/rtems/include/rtems/rtems/messageimpl.h @@ -18,6 +18,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/cpukit/rtems/include/rtems/rtems/regionimpl.h b/cpukit/rtems/include/rtems/rtems/regionimpl.h index 9ff7b966ca..ae1a50d208 100644 --- a/cpukit/rtems/include/rtems/rtems/regionimpl.h +++ b/cpukit/rtems/include/rtems/rtems/regionimpl.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -84,6 +85,7 @@ RTEMS_INLINE_ROUTINE void _Region_Free ( Region_Control *the_region ) { + _Thread_queue_Destroy( &the_region->Wait_queue ); _Objects_Free( &_Region_Information, &the_region->Object ); } diff --git a/cpukit/rtems/src/regioncreate.c b/cpukit/rtems/src/regioncreate.c index 0daf644ce3..aa95f3231b 100644 --- a/cpukit/rtems/src/regioncreate.c +++ b/cpukit/rtems/src/regioncreate.c @@ -71,6 +71,12 @@ rtems_status_code rtems_region_create( return_status = RTEMS_TOO_MANY; else { + _Thread_queue_Initialize( + &the_region->Wait_queue, + _Attributes_Is_priority( attribute_set ) ? + THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, + RTEMS_TIMEOUT + ); the_region->maximum_segment_size = _Heap_Initialize( &the_region->Memory, starting_address, length, page_size @@ -79,23 +85,13 @@ rtems_status_code rtems_region_create( if ( !the_region->maximum_segment_size ) { _Region_Free( the_region ); return_status = RTEMS_INVALID_SIZE; - } - - else { - + } else { the_region->starting_address = starting_address; the_region->length = length; the_region->page_size = page_size; the_region->attribute_set = attribute_set; the_region->number_of_used_blocks = 0; - _Thread_queue_Initialize( - &the_region->Wait_queue, - _Attributes_Is_priority( attribute_set ) ? - THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, - RTEMS_TIMEOUT - ); - _Objects_Open( &_Region_Information, &the_region->Object, diff --git a/cpukit/rtems/src/regiongetsegment.c b/cpukit/rtems/src/regiongetsegment.c index 1a52bc1d59..cef90e79f3 100644 --- a/cpukit/rtems/src/regiongetsegment.c +++ b/cpukit/rtems/src/regiongetsegment.c @@ -79,13 +79,10 @@ rtems_status_code rtems_region_get_segment( _Thread_Disable_dispatch(); _RTEMS_Unlock_allocator(); - executing->Wait.queue = &the_region->Wait_queue; executing->Wait.id = id; executing->Wait.count = size; executing->Wait.return_argument = segment; - _Thread_queue_Enter_critical_section( &the_region->Wait_queue ); - _Thread_queue_Enqueue( &the_region->Wait_queue, executing, diff --git a/cpukit/rtems/src/semdelete.c b/cpukit/rtems/src/semdelete.c index a805ac61de..e9c3ad21e9 100644 --- a/cpukit/rtems/src/semdelete.c +++ b/cpukit/rtems/src/semdelete.c @@ -76,12 +76,14 @@ rtems_status_code rtems_semaphore_delete( SEMAPHORE_MP_OBJECT_WAS_DELETED, CORE_MUTEX_WAS_DELETED ); + _CORE_mutex_Destroy( &the_semaphore->Core_control.mutex ); } else { _CORE_semaphore_Flush( &the_semaphore->Core_control.semaphore, SEMAPHORE_MP_OBJECT_WAS_DELETED, CORE_SEMAPHORE_WAS_DELETED ); + _CORE_semaphore_Destroy( &the_semaphore->Core_control.semaphore ); } _Objects_Close( &_Semaphore_Information, &the_semaphore->Object ); diff --git a/cpukit/score/include/rtems/score/corebarrierimpl.h b/cpukit/score/include/rtems/score/corebarrierimpl.h index 124ecabf05..e8b330dcb6 100644 --- a/cpukit/score/include/rtems/score/corebarrierimpl.h +++ b/cpukit/score/include/rtems/score/corebarrierimpl.h @@ -21,6 +21,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -83,6 +84,13 @@ void _CORE_barrier_Initialize( CORE_barrier_Attributes *the_barrier_attributes ); +RTEMS_INLINE_ROUTINE void _CORE_barrier_Destroy( + CORE_barrier_Control *the_barrier +) +{ + _Thread_queue_Destroy( &the_barrier->Wait_queue ); +} + /** * @brief Wait for the barrier. * diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index e019b0abab..a6811680ff 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -119,6 +119,11 @@ CORE_mutex_Status _CORE_mutex_Initialize( bool initially_locked ); +RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex ) +{ + _Thread_queue_Destroy( &the_mutex->Wait_queue ); +} + /** * @brief Attempt to receive a unit from the_mutex. * diff --git a/cpukit/score/include/rtems/score/corerwlockimpl.h b/cpukit/score/include/rtems/score/corerwlockimpl.h index 331510ba02..e619574d89 100644 --- a/cpukit/score/include/rtems/score/corerwlockimpl.h +++ b/cpukit/score/include/rtems/score/corerwlockimpl.h @@ -21,6 +21,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -87,6 +88,13 @@ void _CORE_RWLock_Initialize( CORE_RWLock_Attributes *the_rwlock_attributes ); +RTEMS_INLINE_ROUTINE void _CORE_RWLock_Destroy( + CORE_RWLock_Control *the_rwlock +) +{ + _Thread_queue_Destroy( &the_rwlock->Wait_queue ); +} + /** * @brief Obtain RWLock for reading. * diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index 6a3a212f34..fac9f689e4 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -98,6 +98,13 @@ void _CORE_semaphore_Initialize( uint32_t initial_value ); +RTEMS_INLINE_ROUTINE void _CORE_semaphore_Destroy( + CORE_semaphore_Control *the_semaphore +) +{ + _Thread_queue_Destroy( &the_semaphore->Wait_queue ); +} + #if defined(RTEMS_SCORE_CORESEM_ENABLE_SEIZE_BODY) /** * This routine attempts to receive a unit from @a the_semaphore. @@ -234,16 +241,14 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Seize_isr_disable( } _Thread_Disable_dispatch(); - _Thread_queue_Enter_critical_section( &the_semaphore->Wait_queue ); - executing->Wait.queue = &the_semaphore->Wait_queue; - executing->Wait.id = id; - _ISR_lock_ISR_enable( lock_context ); - - _Thread_queue_Enqueue( + executing->Wait.id = id; + _Thread_queue_Acquire_critical( &the_semaphore->Wait_queue, lock_context ); + _Thread_queue_Enqueue_critical( &the_semaphore->Wait_queue, executing, STATES_WAITING_FOR_SEMAPHORE, - timeout + timeout, + lock_context ); _Thread_Enable_dispatch(); } diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index 00b9221356..1f99ffde04 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -20,6 +20,7 @@ #define _RTEMS_SCORE_THREADQ_H #include +#include #include #include #include @@ -62,6 +63,18 @@ typedef struct { /** This is the set of threads for priority discipline waiting. */ RBTree_Control Priority; } Queues; + + /** + * @brief Lock to protect this thread queue. + * + * It may be used to protect additional state of the object embedding this + * thread queue. + * + * @see _Thread_queue_Acquire(), _Thread_queue_Acquire_critical() and + * _Thread_queue_Release(). + */ + ISR_LOCK_MEMBER( Lock ) + /** This field is used to manage the critical section. */ Thread_blocking_operation_States sync_state; /** This field indicates the thread queue's blocking discipline. */ diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 6fc38cfa5b..3595dc5d85 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -31,6 +31,31 @@ extern "C" { */ /**@{*/ +RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical( + Thread_queue_Control *the_thread_queue, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Acquire( &the_thread_queue->Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire( + Thread_queue_Control *the_thread_queue, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_ISR_disable( lock_context ); + _Thread_queue_Acquire_critical( the_thread_queue, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Thread_queue_Release( + Thread_queue_Control *the_thread_queue, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Release_and_ISR_enable( &the_thread_queue->Lock, lock_context ); +} + /** * The following type defines the callout used when a remote task * is extracted from a local thread queue. @@ -55,26 +80,48 @@ Thread_Control *_Thread_queue_Dequeue( ); /** - * @brief Blocks a thread and places it on a thread. + * @brief Blocks a thread and places it on a thread queue. * - * This routine blocks a thread, places it on a thread, and optionally - * starts a timeout timer. + * This routine blocks a thread, places it on a thread queue, and optionally + * starts a watchdog in case the timeout interval is not WATCHDOG_NO_TIMEOUT. * - * @param[in] the_thread_queue pointer to threadq - * @param[in] the_thread the thread to enqueue - * @param[in] state is the new state of the thread - * @param[in] timeout interval to wait + * The caller must be the owner of the thread queue lock. This function will + * release the thread queue lock and register it as the new thread lock. * - * - INTERRUPT LATENCY: - * + single case + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to enqueue. + * @param[in] state The new state of the thread. + * @param[in] timeout Interval to wait. Use WATCHDOG_NO_TIMEOUT to block + * potentially forever. + * @param[in] lock_context The lock context of the lock acquire. */ -void _Thread_queue_Enqueue( +void _Thread_queue_Enqueue_critical( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, States_Control state, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); +RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + States_Control state, + Watchdog_Interval timeout +) +{ + ISR_lock_Context lock_context; + + _Thread_queue_Acquire( the_thread_queue, &lock_context ); + _Thread_queue_Enqueue_critical( + the_thread_queue, + the_thread, + state, + timeout, + &lock_context + ); +} + /** * @brief Extracts thread from thread queue. * @@ -116,15 +163,30 @@ void _Thread_queue_Extract_with_proxy( ); /** - * @brief Gets a pointer to the "first" thread on the_thread_queue. + * @brief Returns the first thread on the thread queue if it exists, otherwise + * @c NULL (locked). + * + * The caller must be the owner of the thread queue lock. + * + * @param[in] the_thread_queue The thread queue. * - * This function returns a pointer to the "first" thread - * on the_thread_queue. The "first" thread is selected - * based on the discipline of the_thread_queue. + * @retval NULL No thread is present on the thread queue. + * @retval first The first thread on the thread queue according to the enqueue + * order. + */ +Thread_Control *_Thread_queue_First_locked( + Thread_queue_Control *the_thread_queue +); + +/** + * @brief Returns the first thread on the thread queue if it exists, otherwise + * @c NULL. * - * @param[in] the_thread_queue pointer to thread queue + * @param[in] the_thread_queue The thread queue. * - * @retval first thread or NULL + * @retval NULL No thread is present on the thread queue. + * @retval first The first thread on the thread queue according to the enqueue + * order. */ Thread_Control *_Thread_queue_First( Thread_queue_Control *the_thread_queue @@ -165,6 +227,13 @@ void _Thread_queue_Initialize( uint32_t timeout_status ); +RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy( + Thread_queue_Control *the_thread_queue +) +{ + _ISR_lock_Destroy( &the_thread_queue->Lock ); +} + /** * @brief Thread queue timeout. * @@ -212,17 +281,6 @@ RBTree_Compare_result _Thread_queue_Compare_priority( const RBTree_Node *right ); -/** - * This routine is invoked to indicate that the specified thread queue is - * entering a critical section. - */ -RTEMS_INLINE_ROUTINE void _Thread_queue_Enter_critical_section ( - Thread_queue_Control *the_thread_queue -) -{ - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; -} - /**@}*/ #ifdef __cplusplus diff --git a/cpukit/score/src/corebarrierwait.c b/cpukit/score/src/corebarrierwait.c index 6267ae67c0..30abf0c17a 100644 --- a/cpukit/score/src/corebarrierwait.c +++ b/cpukit/score/src/corebarrierwait.c @@ -32,30 +32,28 @@ void _CORE_barrier_Wait( CORE_barrier_API_mp_support_callout api_barrier_mp_support ) { - ISR_Level level; + ISR_lock_Context lock_context; executing->Wait.return_code = CORE_BARRIER_STATUS_SUCCESSFUL; - _ISR_Disable( level ); + _Thread_queue_Acquire( &the_barrier->Wait_queue, &lock_context ); the_barrier->number_of_waiting_threads++; if ( _CORE_barrier_Is_automatic( &the_barrier->Attributes ) ) { if ( the_barrier->number_of_waiting_threads == the_barrier->Attributes.maximum_count) { executing->Wait.return_code = CORE_BARRIER_STATUS_AUTOMATICALLY_RELEASED; - _ISR_Enable( level ); + _Thread_queue_Release( &the_barrier->Wait_queue, &lock_context ); _CORE_barrier_Release( the_barrier, id, api_barrier_mp_support ); return; } } - _Thread_queue_Enter_critical_section( &the_barrier->Wait_queue ); - executing->Wait.queue = &the_barrier->Wait_queue; - executing->Wait.id = id; - _ISR_Enable( level ); + executing->Wait.id = id; - _Thread_queue_Enqueue( + _Thread_queue_Enqueue_critical( &the_barrier->Wait_queue, executing, STATES_WAITING_FOR_BARRIER, - timeout + timeout, + &lock_context ); } diff --git a/cpukit/score/src/coremsgclose.c b/cpukit/score/src/coremsgclose.c index 987f038cb3..17ecc4428e 100644 --- a/cpukit/score/src/coremsgclose.c +++ b/cpukit/score/src/coremsgclose.c @@ -54,4 +54,5 @@ void _CORE_message_queue_Close( (void) _Workspace_Free( the_message_queue->message_buffers ); + _Thread_queue_Destroy( &the_message_queue->Wait_queue ); } diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c index db8d558ca6..45105ca19b 100644 --- a/cpukit/score/src/coremsgseize.c +++ b/cpukit/score/src/coremsgseize.c @@ -36,15 +36,15 @@ void _CORE_message_queue_Seize( Watchdog_Interval timeout ) { - ISR_Level level; + ISR_lock_Context lock_context; CORE_message_queue_Buffer_control *the_message; executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; - _ISR_Disable( level ); + _Thread_queue_Acquire( &the_message_queue->Wait_queue, &lock_context ); the_message = _CORE_message_queue_Get_pending_message( the_message_queue ); if ( the_message != NULL ) { the_message_queue->number_of_pending_messages -= 1; - _ISR_Enable( level ); + _Thread_queue_Release( &the_message_queue->Wait_queue, &lock_context ); *size_p = the_message->Contents.size; executing->Wait.count = @@ -109,23 +109,21 @@ void _CORE_message_queue_Seize( } if ( !wait ) { - _ISR_Enable( level ); + _Thread_queue_Release( &the_message_queue->Wait_queue, &lock_context ); executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT; return; } - _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue ); - executing->Wait.queue = &the_message_queue->Wait_queue; executing->Wait.id = id; executing->Wait.return_argument_second.mutable_object = buffer; executing->Wait.return_argument = size_p; /* Wait.count will be filled in with the message priority */ - _ISR_Enable( level ); - _Thread_queue_Enqueue( + _Thread_queue_Enqueue_critical( &the_message_queue->Wait_queue, executing, STATES_WAITING_FOR_MESSAGE, - timeout + timeout, + &lock_context ); } diff --git a/cpukit/score/src/coremsgsubmit.c b/cpukit/score/src/coremsgsubmit.c index 4437856b17..0bcebe04af 100644 --- a/cpukit/score/src/coremsgsubmit.c +++ b/cpukit/score/src/coremsgsubmit.c @@ -120,16 +120,10 @@ CORE_message_queue_Status _CORE_message_queue_Submit( * would be to use this variable prior to here. */ { - ISR_Level level; - - _ISR_Disable( level ); - _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue ); - executing->Wait.queue = &the_message_queue->Wait_queue; executing->Wait.id = id; executing->Wait.return_argument_second.immutable_object = buffer; executing->Wait.option = (uint32_t) size; executing->Wait.count = submit_type; - _ISR_Enable( level ); _Thread_queue_Enqueue( &the_message_queue->Wait_queue, diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 3fc3765ef4..67954b697b 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -53,27 +53,35 @@ void _CORE_mutex_Seize_interrupt_blocking( ISR_lock_Context *lock_context ) { - _Thread_queue_Enter_critical_section( &the_mutex->Wait_queue ); - executing->Wait.queue = &the_mutex->Wait_queue; _Thread_Disable_dispatch(); - _ISR_lock_ISR_enable( lock_context ); if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) { Thread_Control *holder = the_mutex->holder; + /* + * To enable interrupts here works only since we own the Giant lock and + * only threads are allowed to seize and surrender mutexes with the + * priority inheritance protocol. + */ + _ISR_lock_ISR_enable( lock_context ); + _Scheduler_Change_priority_if_higher( _Scheduler_Get( holder ), holder, executing->current_priority, false ); + + _ISR_lock_ISR_disable( lock_context ); } - _Thread_queue_Enqueue( + _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context ); + _Thread_queue_Enqueue_critical( &the_mutex->Wait_queue, executing, STATES_WAITING_FOR_MUTEX, - timeout + timeout, + lock_context ); _Thread_Enable_dispatch(); diff --git a/cpukit/score/src/corerwlockobtainread.c b/cpukit/score/src/corerwlockobtainread.c index 203680f6dc..59c1097354 100644 --- a/cpukit/score/src/corerwlockobtainread.c +++ b/cpukit/score/src/corerwlockobtainread.c @@ -32,7 +32,7 @@ void _CORE_RWLock_Obtain_for_reading( CORE_RWLock_API_mp_support_callout api_rwlock_mp_support ) { - ISR_Level level; + ISR_lock_Context lock_context; /* * If unlocked, then OK to read. @@ -40,21 +40,21 @@ void _CORE_RWLock_Obtain_for_reading( * If any thread is waiting, then we wait. */ - _ISR_Disable( level ); + _Thread_queue_Acquire( &the_rwlock->Wait_queue, &lock_context ); switch ( the_rwlock->current_state ) { case CORE_RWLOCK_UNLOCKED: the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; the_rwlock->number_of_readers += 1; - _ISR_Enable( level ); + _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; return; case CORE_RWLOCK_LOCKED_FOR_READING: { Thread_Control *waiter; - waiter = _Thread_queue_First( &the_rwlock->Wait_queue ); + waiter = _Thread_queue_First_locked( &the_rwlock->Wait_queue ); if ( !waiter ) { the_rwlock->number_of_readers += 1; - _ISR_Enable( level ); + _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; return; } @@ -69,7 +69,7 @@ void _CORE_RWLock_Obtain_for_reading( */ if ( !wait ) { - _ISR_Enable( level ); + _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; return; } @@ -78,18 +78,16 @@ void _CORE_RWLock_Obtain_for_reading( * We need to wait to enter this critical section */ - _Thread_queue_Enter_critical_section( &the_rwlock->Wait_queue ); - executing->Wait.queue = &the_rwlock->Wait_queue; executing->Wait.id = id; executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ; executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - _ISR_Enable( level ); - _Thread_queue_Enqueue( + _Thread_queue_Enqueue_critical( &the_rwlock->Wait_queue, executing, STATES_WAITING_FOR_RWLOCK, - timeout + timeout, + &lock_context ); /* return to API level so it can dispatch and we block */ diff --git a/cpukit/score/src/corerwlockobtainwrite.c b/cpukit/score/src/corerwlockobtainwrite.c index 3499bcd4c8..409d31aeec 100644 --- a/cpukit/score/src/corerwlockobtainwrite.c +++ b/cpukit/score/src/corerwlockobtainwrite.c @@ -32,7 +32,7 @@ void _CORE_RWLock_Obtain_for_writing( CORE_RWLock_API_mp_support_callout api_rwlock_mp_support ) { - ISR_Level level; + ISR_lock_Context lock_context; /* * If unlocked, then OK to read. @@ -41,13 +41,13 @@ void _CORE_RWLock_Obtain_for_writing( * If any thread is waiting, then we wait. */ - _ISR_Disable( level ); + _Thread_queue_Acquire( &the_rwlock->Wait_queue, &lock_context ); switch ( the_rwlock->current_state ) { case CORE_RWLOCK_UNLOCKED: - the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; - _ISR_Enable( level ); - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - return; + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; + _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; case CORE_RWLOCK_LOCKED_FOR_READING: case CORE_RWLOCK_LOCKED_FOR_WRITING: @@ -59,7 +59,7 @@ void _CORE_RWLock_Obtain_for_writing( */ if ( !wait ) { - _ISR_Enable( level ); + _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; return; } @@ -68,18 +68,16 @@ void _CORE_RWLock_Obtain_for_writing( * We need to wait to enter this critical section */ - _Thread_queue_Enter_critical_section( &the_rwlock->Wait_queue ); - executing->Wait.queue = &the_rwlock->Wait_queue; executing->Wait.id = id; executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE; executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - _ISR_Enable( level ); - _Thread_queue_Enqueue( + _Thread_queue_Enqueue_critical( &the_rwlock->Wait_queue, executing, STATES_WAITING_FOR_RWLOCK, - timeout + timeout, + &lock_context ); /* return to API level so it can dispatch and we block */ diff --git a/cpukit/score/src/coresemseize.c b/cpukit/score/src/coresemseize.c index 9c0db96204..d7ab28e779 100644 --- a/cpukit/score/src/coresemseize.c +++ b/cpukit/score/src/coresemseize.c @@ -34,13 +34,13 @@ void _CORE_semaphore_Seize( Watchdog_Interval timeout ) { - ISR_Level level; + ISR_lock_Context lock_context; executing->Wait.return_code = CORE_SEMAPHORE_STATUS_SUCCESSFUL; - _ISR_Disable( level ); + _Thread_queue_Acquire( &the_semaphore->Wait_queue, &lock_context ); if ( the_semaphore->count != 0 ) { the_semaphore->count -= 1; - _ISR_Enable( level ); + _Thread_queue_Release( &the_semaphore->Wait_queue, &lock_context ); return; } @@ -50,7 +50,7 @@ void _CORE_semaphore_Seize( * the semaphore was not available and the caller never blocked. */ if ( !wait ) { - _ISR_Enable( level ); + _Thread_queue_Release( &the_semaphore->Wait_queue, &lock_context ); executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT; return; } @@ -59,15 +59,13 @@ void _CORE_semaphore_Seize( * If the semaphore is not available and the caller is willing to * block, then we now block the caller with optional timeout. */ - _Thread_queue_Enter_critical_section( &the_semaphore->Wait_queue ); - executing->Wait.queue = &the_semaphore->Wait_queue; - executing->Wait.id = id; - _ISR_Enable( level ); - _Thread_queue_Enqueue( + executing->Wait.id = id; + _Thread_queue_Enqueue_critical( &the_semaphore->Wait_queue, executing, STATES_WAITING_FOR_SEMAPHORE, - timeout + timeout, + &lock_context ); } #endif diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 424bcb4d33..9915aa2d12 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -206,8 +206,6 @@ uint32_t _MPCI_Send_request_packet ( (*_MPCI_table->send_packet)( destination, the_packet ); - _Thread_queue_Enter_critical_section( &_MPCI_Remote_blocked_threads ); - /* * See if we need a default timeout */ diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c index 0ea0c82d83..47c294e968 100644 --- a/cpukit/score/src/threadq.c +++ b/cpukit/score/src/threadq.c @@ -55,10 +55,11 @@ void _Thread_queue_Initialize( the_thread_queue->timeout_status = timeout_status; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + _ISR_lock_Initialize( &the_thread_queue->Lock, "Thread Queue" ); + if ( the_discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { _RBTree_Initialize_empty( &the_thread_queue->Queues.Priority ); } else { /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ _Chain_Initialize_empty( &the_thread_queue->Queues.Fifo ); } - } diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 590865d8dd..76eaa30dde 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -24,18 +24,6 @@ #include #include -ISR_LOCK_DEFINE( static, _Thread_queue_Lock, "Thread Queue" ) - -static void _Thread_queue_Acquire( ISR_lock_Context *lock_context ) -{ - _ISR_lock_ISR_disable_and_acquire( &_Thread_queue_Lock, lock_context ); -} - -static void _Thread_queue_Release( ISR_lock_Context *lock_context ) -{ - _ISR_lock_Release_and_ISR_enable( &_Thread_queue_Lock, lock_context ); -} - /** * @brief Finalize a blocking operation. * @@ -50,8 +38,9 @@ static void _Thread_queue_Release( ISR_lock_Context *lock_context ) * @param[in] lock_context is the previous ISR disable level */ static void _Thread_blocking_operation_Finalize( - Thread_Control *the_thread, - ISR_lock_Context *lock_context + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { /* @@ -59,16 +48,18 @@ static void _Thread_blocking_operation_Finalize( */ the_thread->Wait.queue = NULL; + _Thread_Lock_restore_default( the_thread ); + /* * If the sync state is timed out, this is very likely not needed. * But better safe than sorry when it comes to critical sections. */ if ( _Watchdog_Is_active( &the_thread->Timer ) ) { _Watchdog_Deactivate( &the_thread->Timer ); - _Thread_queue_Release( lock_context ); + _Thread_queue_Release( the_thread_queue, lock_context ); _Watchdog_Remove_ticks( &the_thread->Timer ); } else - _Thread_queue_Release( lock_context ); + _Thread_queue_Release( the_thread_queue, lock_context ); /* * Global objects with thread queue's should not be operated on from an @@ -101,16 +92,23 @@ static void _Thread_queue_Requeue_priority( ); } -void _Thread_queue_Enqueue( +void _Thread_queue_Enqueue_critical( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, States_Control state, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { - ISR_lock_Context lock_context; Thread_blocking_operation_States sync_state; + _Thread_Lock_set( the_thread, &the_thread_queue->Lock ); + + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + the_thread->Wait.queue = the_thread_queue; + + _Thread_queue_Release( the_thread_queue, lock_context ); + #if defined(RTEMS_MULTIPROCESSING) if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) the_thread = _Thread_MP_Allocate_proxy( state ); @@ -140,7 +138,7 @@ void _Thread_queue_Enqueue( * should be completed or the thread has had its blocking condition * satisfied before we got here. */ - _Thread_queue_Acquire( &lock_context ); + _Thread_queue_Acquire( the_thread_queue, lock_context ); sync_state = the_thread_queue->sync_state; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; @@ -155,7 +153,6 @@ void _Thread_queue_Enqueue( &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ - _Thread_Lock_set( the_thread, &_Thread_queue_Lock ); _Thread_Priority_set_change_handler( the_thread, _Thread_queue_Requeue_priority, @@ -169,9 +166,8 @@ void _Thread_queue_Enqueue( ); } - the_thread->Wait.queue = the_thread_queue; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; - _Thread_queue_Release( &lock_context ); + _Thread_queue_Release( the_thread_queue, lock_context ); } else { /* Cancel a blocking operation due to ISR */ @@ -180,7 +176,7 @@ void _Thread_queue_Enqueue( sync_state == THREAD_BLOCKING_OPERATION_SATISFIED ); - _Thread_blocking_operation_Finalize( the_thread, &lock_context ); + _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, lock_context ); } } @@ -190,16 +186,19 @@ void _Thread_queue_Extract_with_return_code( ) { Thread_queue_Control *the_thread_queue; - ISR_lock_Context lock_context; + ISR_lock_Control *lock; + ISR_lock_Context lock_context; - _Thread_queue_Acquire( &lock_context ); + lock = _Thread_Lock_acquire( the_thread, &lock_context ); the_thread_queue = the_thread->Wait.queue; if ( the_thread_queue == NULL ) { - _Thread_queue_Release( &lock_context ); + _Thread_Lock_release( lock, &lock_context ); return; } + _SMP_Assert( lock == &the_thread_queue->Lock ); + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { _Chain_Extract_unprotected( &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ @@ -208,7 +207,6 @@ void _Thread_queue_Extract_with_return_code( &the_thread->RBNode ); _Thread_Priority_restore_default_change_handler( the_thread ); - _Thread_Lock_restore_default( the_thread ); } the_thread->Wait.return_code = return_code; @@ -218,7 +216,7 @@ void _Thread_queue_Extract_with_return_code( * * NOTE: This is invoked with interrupts still disabled. */ - _Thread_blocking_operation_Finalize( the_thread, &lock_context ); + _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, &lock_context ); } void _Thread_queue_Extract( Thread_Control *the_thread ) @@ -238,7 +236,7 @@ Thread_Control *_Thread_queue_Dequeue( Thread_blocking_operation_States sync_state; the_thread = NULL; - _Thread_queue_Acquire( &lock_context ); + _Thread_queue_Acquire( the_thread_queue, &lock_context ); /* * Invoke the discipline specific dequeue method. @@ -255,7 +253,6 @@ Thread_Control *_Thread_queue_Dequeue( if ( first ) { the_thread = THREAD_RBTREE_NODE_TO_THREAD( first ); _Thread_Priority_restore_default_change_handler( the_thread ); - _Thread_Lock_restore_default( the_thread ); } } @@ -270,7 +267,7 @@ Thread_Control *_Thread_queue_Dequeue( the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SATISFIED; the_thread = _Thread_Executing; } else { - _Thread_queue_Release( &lock_context ); + _Thread_queue_Release( the_thread_queue, &lock_context ); return NULL; } } @@ -280,7 +277,7 @@ Thread_Control *_Thread_queue_Dequeue( * * NOTE: This is invoked with interrupts still disabled. */ - _Thread_blocking_operation_Finalize( the_thread, &lock_context ); + _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, &lock_context ); return the_thread; } diff --git a/cpukit/score/src/threadqfirst.c b/cpukit/score/src/threadqfirst.c index 5d97ae156d..f43b9abbd0 100644 --- a/cpukit/score/src/threadqfirst.c +++ b/cpukit/score/src/threadqfirst.c @@ -20,20 +20,16 @@ #include #include -#include #include -Thread_Control *_Thread_queue_First( +Thread_Control *_Thread_queue_First_locked( Thread_queue_Control *the_thread_queue ) { - ISR_Level level; Thread_Control *thread; thread = NULL; - _ISR_Disable( level ); - if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) thread = (Thread_Control *) _Chain_First(&the_thread_queue->Queues.Fifo); @@ -45,7 +41,19 @@ Thread_Control *_Thread_queue_First( thread = THREAD_RBTREE_NODE_TO_THREAD( first ); } - _ISR_Enable( level ); - return thread; } + +Thread_Control *_Thread_queue_First( + Thread_queue_Control *the_thread_queue +) +{ + Thread_Control *the_thread; + ISR_lock_Context lock_context; + + _Thread_queue_Acquire( the_thread_queue, &lock_context ); + the_thread = _Thread_queue_First_locked( the_thread_queue ); + _Thread_queue_Release( the_thread_queue, &lock_context ); + + return the_thread; +} -- cgit v1.2.3 From 568af83542eec9343c24d417ed6a219d22046233 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 21 Apr 2015 10:17:13 +0200 Subject: score: Add Thread_queue_Operations Replace the Thread_Priority_control with more general Thread_queue_Operations which will be used for generic priority change, timeout, signal and wait queue operations in the future. Update #2273. --- cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/thread.h | 86 +++++++++---------------- cpukit/score/include/rtems/score/threadimpl.h | 88 ++++++++++++++++---------- cpukit/score/include/rtems/score/threadq.h | 49 +++++++++++++- cpukit/score/include/rtems/score/threadqimpl.h | 6 ++ cpukit/score/src/thread.c | 2 +- cpukit/score/src/threadchangepriority.c | 10 +-- cpukit/score/src/threadinitialize.c | 13 +--- cpukit/score/src/threadqenqueue.c | 30 ++------- cpukit/score/src/threadqops.c | 56 ++++++++++++++++ testsuites/sptests/spintrcritical23/init.c | 4 +- 11 files changed, 207 insertions(+), 138 deletions(-) create mode 100644 cpukit/score/src/threadqops.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 35470972af..18becdb300 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -302,6 +302,7 @@ libscore_a_SOURCES += src/threadq.c \ src/threadqenqueue.c \ src/threadqextractwithproxy.c src/threadqfirst.c \ src/threadqflush.c src/threadqprocesstimeout.c src/threadqtimeout.c +libscore_a_SOURCES += src/threadqops.c ## TIMESPEC_C_FILES libscore_a_SOURCES += src/timespecaddto.c src/timespecfromticks.c \ diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index 1a73fdaa8a..bce6f5643e 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -248,56 +248,6 @@ typedef struct { void *tls_area; } Thread_Start_information; -/** - * @brief Priority change handler. - * - * @param[in] the_thread The thread. - * @param[in] new_priority The new priority value. - * @param[in] context The handler context. - * - * @see _Thread_Priority_set_change_handler(). - */ -typedef void (*Thread_Priority_change_handler)( - Thread_Control *the_thread, - Priority_Control new_priority, - void *context -); - -/** - * @brief Thread priority control. - */ -typedef struct { - /** - * @brief Generation of the current priority value. - * - * It is used in _Thread_Change_priority() to serialize the update of - * priority related data structures. - */ - uint32_t generation; - - /** - * @brief Priority change handler. - * - * Called by _Thread_Change_priority() to notify a thread about a priority - * change. In case this thread waits currently for a resource the handler - * may adjust its data structures according to the new priority value. This - * handler must not be NULL, instead the default handler - * _Thread_Priority_change_do_nothing() should be used in case nothing needs - * to be done during a priority change. - * - * @see _Thread_Priority_set_change_handler() and - * _Thread_Priority_restore_default_change_handler(). - */ - Thread_Priority_change_handler change_handler; - - /** - * @brief Context for priority change handler. - * - * @see _Thread_Priority_set_change_handler(). - */ - void *change_handler_context; -} Thread_Priority_control; - /** * @brief Union type to hold a pointer to an immutable or a mutable object. * @@ -359,7 +309,14 @@ typedef struct { */ uint32_t timeout_code; - /** This field points to the thread queue on which this thread is blocked. */ + /** + * @brief The current thread queue. + * + * In case this field is @c NULL, then the thread is not blocked on a thread + * queue. This field is protected by the thread lock. + * + * @see _Thread_Lock_set() and _Thread_Wait_set_queue(). + */ Thread_queue_Control *queue; /** @@ -371,6 +328,15 @@ typedef struct { #else Thread_Wait_flags flags; #endif + + /** + * @brief The current thread queue operations. + * + * This field is protected by the thread lock. + * + * @see _Thread_Lock_set() and _Thread_Wait_set_operations(). + */ + const Thread_queue_Operations *operations; } Thread_Wait_information; /** @@ -393,9 +359,12 @@ typedef struct { Priority_Control real_priority; /** - * @brief Thread priority control. + * @brief Generation of the current priority value. + * + * It is used in _Thread_Change_priority() to serialize the update of + * priority related data structures. */ - Thread_Priority_control Priority; + uint32_t priority_generation; /** This field is the number of mutexes currently held by this proxy. */ uint32_t resource_count; @@ -638,8 +607,8 @@ typedef struct { * * The thread lock protects the following thread variables * - Thread_Control::current_priority, - * - Thread_Control::Priority::change_handler, and - * - Thread_Control::Priority::change_handler_context. + * - Thread_Control::Wait::queue, and + * - Thread_Control::Wait::operations. * * @see _Thread_Lock_acquire(), _Thread_Lock_release(), _Thread_Lock_set() and * _Thread_Lock_restore_default(). @@ -679,9 +648,12 @@ struct Thread_Control_struct { Priority_Control real_priority; /** - * @brief Thread priority control. + * @brief Generation of the current priority value. + * + * It is used in _Thread_Change_priority() to serialize the update of + * priority related data structures. */ - Thread_Priority_control Priority; + uint32_t priority_generation; /** This field is the number of mutexes currently held by this thread. */ uint32_t resource_count; diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index c266a9cce3..953b88b925 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -1078,41 +1079,6 @@ RTEMS_INLINE_ROUTINE void _Thread_Lock_restore_default( do { } while ( 0 ) #endif -void _Thread_Priority_change_do_nothing( - Thread_Control *the_thread, - Priority_Control new_priority, - void *context -); - -/** - * @brief Sets the thread priority change handler and its context. - * - * @param[in] the_thread The thread. - * @param[in] new_handler The new handler. - * @param[in] new_context The new handler context. - */ -RTEMS_INLINE_ROUTINE void _Thread_Priority_set_change_handler( - Thread_Control *the_thread, - Thread_Priority_change_handler new_handler, - void *new_context -) -{ - the_thread->Priority.change_handler = new_handler; - the_thread->Priority.change_handler_context = new_context; -} - -/** - * @brief Restores the thread priority change default handler and its context. - * - * @param[in] the_thread The thread. - */ -RTEMS_INLINE_ROUTINE void _Thread_Priority_restore_default_change_handler( - Thread_Control *the_thread -) -{ - the_thread->Priority.change_handler = _Thread_Priority_change_do_nothing; -} - /** * @brief The initial thread wait flags value set by _Thread_Initialize(). */ @@ -1257,6 +1223,58 @@ RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change( return success; } +/** + * @brief Sets the thread queue. + * + * The caller must be the owner of the thread lock. + * + * @param[in] the_thread The thread. + * @param[in] new_queue The new queue. + * + * @see _Thread_Lock_set(). + */ +RTEMS_INLINE_ROUTINE void _Thread_Wait_set_queue( + Thread_Control *the_thread, + Thread_queue_Control *new_queue +) +{ + the_thread->Wait.queue = new_queue; +} + +/** + * @brief Sets the thread queue operations. + * + * The caller must be the owner of the thread lock. + * + * @param[in] the_thread The thread. + * @param[in] new_operations The new queue operations. + * + * @see _Thread_Lock_set() and _Thread_Wait_restore_default_operations(). + */ +RTEMS_INLINE_ROUTINE void _Thread_Wait_set_operations( + Thread_Control *the_thread, + const Thread_queue_Operations *new_operations +) +{ + the_thread->Wait.operations = new_operations; +} + +/** + * @brief Restores the default thread queue operations. + * + * The caller must be the owner of the thread lock. + * + * @param[in] the_thread The thread. + * + * @see _Thread_Wait_set_operations(). + */ +RTEMS_INLINE_ROUTINE void _Thread_Wait_restore_default_operations( + Thread_Control *the_thread +) +{ + the_thread->Wait.operations = &_Thread_queue_Operations_default; +} + /** * @brief Sets the thread wait timeout code. * diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index 1f99ffde04..c483b87620 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -21,9 +21,11 @@ #include #include +#include +#include +#include #include #include -#include #ifdef __cplusplus extern "C" { @@ -40,6 +42,42 @@ extern "C" { */ /**@{*/ +typedef struct Thread_queue_Control Thread_queue_Control; + +/** + * @brief Thread queue priority change operation. + * + * @param[in] the_thread The thread. + * @param[in] new_priority The new priority value. + * @param[in] queue The thread queue. + * + * @see Thread_queue_Operations. + */ +typedef void ( *Thread_queue_Priority_change_operation )( + Thread_Control *the_thread, + Priority_Control new_priority, + Thread_queue_Control *queue +); + +/** + * @brief Thread queue operations. + * + * @see _Thread_wait_Set_operations(). + */ +typedef struct { + /** + * @brief Thread queue priority change operation. + * + * Called by _Thread_Change_priority() to notify a thread about a priority + * change. In case this thread waits currently for a resource the handler + * may adjust its data structures according to the new priority value. This + * handler must not be NULL, instead the default handler + * _Thread_Do_nothing_priority_change() should be used in case nothing needs + * to be done during a priority change. + */ + Thread_queue_Priority_change_operation priority_change; +} Thread_queue_Operations; + /** * The following enumerated type details all of the disciplines * supported by the Thread Queue Handler. @@ -53,7 +91,7 @@ typedef enum { * This is the structure used to manage sets of tasks which are blocked * waiting to acquire a resource. */ -typedef struct { +struct Thread_queue_Control { /** This union contains the data structures used to manage the blocked * set of tasks which varies based upon the discipline. */ @@ -64,6 +102,11 @@ typedef struct { RBTree_Control Priority; } Queues; + /** + * @brief The operations for this thread queue. + */ + const Thread_queue_Operations *operations; + /** * @brief Lock to protect this thread queue. * @@ -83,7 +126,7 @@ typedef struct { * waiting on this thread queue. */ uint32_t timeout_status; -} Thread_queue_Control; +}; /**@}*/ diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 3595dc5d85..04e67309b2 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -281,6 +281,12 @@ RBTree_Compare_result _Thread_queue_Compare_priority( const RBTree_Node *right ); +extern const Thread_queue_Operations _Thread_queue_Operations_default; + +extern const Thread_queue_Operations _Thread_queue_Operations_FIFO; + +extern const Thread_queue_Operations _Thread_queue_Operations_priority; + /**@}*/ #ifdef __cplusplus diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c index 88b3272d0a..f4c53079d5 100644 --- a/cpukit/score/src/thread.c +++ b/cpukit/score/src/thread.c @@ -32,7 +32,7 @@ THREAD_OFFSET_ASSERT( RBNode ); THREAD_OFFSET_ASSERT( current_state ); THREAD_OFFSET_ASSERT( current_priority ); THREAD_OFFSET_ASSERT( real_priority ); -THREAD_OFFSET_ASSERT( Priority ); +THREAD_OFFSET_ASSERT( priority_generation ); THREAD_OFFSET_ASSERT( resource_count ); THREAD_OFFSET_ASSERT( Wait ); THREAD_OFFSET_ASSERT( Timer ); diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c index a011a8f5e5..3223544fe3 100644 --- a/cpukit/score/src/threadchangepriority.c +++ b/cpukit/score/src/threadchangepriority.c @@ -41,21 +41,21 @@ void _Thread_Change_priority( if ( the_thread->current_priority != new_priority ) { uint32_t my_generation; - my_generation = the_thread->Priority.generation + 1; + my_generation = the_thread->priority_generation + 1; the_thread->current_priority = new_priority; - the_thread->Priority.generation = my_generation; + the_thread->priority_generation = my_generation; - (*the_thread->Priority.change_handler)( + ( *the_thread->Wait.operations->priority_change )( the_thread, new_priority, - the_thread->Priority.change_handler_context + the_thread->Wait.queue ); _Thread_Lock_release( lock, &lock_context ); _Scheduler_Acquire( the_thread, &lock_context ); - if ( the_thread->Priority.generation == my_generation ) { + if ( the_thread->priority_generation == my_generation ) { if ( _States_Is_ready( the_thread->current_state ) ) { _Scheduler_Change_priority( the_thread, diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 27c3f06af7..9f5df257aa 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -29,15 +29,6 @@ #include #include -void _Thread_Priority_change_do_nothing( - Thread_Control *the_thread, - Priority_Control new_priority, - void *context -) -{ - /* Do nothing */ -} - bool _Thread_Initialize( Objects_Information *information, Thread_Control *the_thread, @@ -208,10 +199,10 @@ bool _Thread_Initialize( the_thread->current_state = STATES_DORMANT; the_thread->Wait.queue = NULL; + the_thread->Wait.operations = &_Thread_queue_Operations_default; the_thread->resource_count = 0; the_thread->real_priority = priority; - the_thread->Priority.generation = 0; - the_thread->Priority.change_handler = _Thread_Priority_change_do_nothing; + the_thread->priority_generation = 0; the_thread->Start.initial_priority = priority; _Thread_Wait_flags_set( the_thread, THREAD_WAIT_FLAGS_INITIAL ); diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 76eaa30dde..6cc731e282 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -46,7 +46,7 @@ static void _Thread_blocking_operation_Finalize( /* * The thread is not waiting on anything after this completes. */ - the_thread->Wait.queue = NULL; + _Thread_Wait_set_queue( the_thread, NULL ); _Thread_Lock_restore_default( the_thread ); @@ -75,23 +75,6 @@ static void _Thread_blocking_operation_Finalize( #endif } -static void _Thread_queue_Requeue_priority( - Thread_Control *the_thread, - Priority_Control new_priority, - void *context -) -{ - Thread_queue_Control *tq = context; - - _RBTree_Extract( &tq->Queues.Priority, &the_thread->RBNode ); - _RBTree_Insert( - &tq->Queues.Priority, - &the_thread->RBNode, - _Thread_queue_Compare_priority, - false - ); -} - void _Thread_queue_Enqueue_critical( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, @@ -105,7 +88,7 @@ void _Thread_queue_Enqueue_critical( _Thread_Lock_set( the_thread, &the_thread_queue->Lock ); the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; - the_thread->Wait.queue = the_thread_queue; + _Thread_Wait_set_queue( the_thread, the_thread_queue ); _Thread_queue_Release( the_thread_queue, lock_context ); @@ -153,10 +136,9 @@ void _Thread_queue_Enqueue_critical( &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ - _Thread_Priority_set_change_handler( + _Thread_Wait_set_operations( the_thread, - _Thread_queue_Requeue_priority, - the_thread_queue + &_Thread_queue_Operations_priority ); _RBTree_Insert( &the_thread_queue->Queues.Priority, @@ -206,7 +188,7 @@ void _Thread_queue_Extract_with_return_code( &the_thread->Wait.queue->Queues.Priority, &the_thread->RBNode ); - _Thread_Priority_restore_default_change_handler( the_thread ); + _Thread_Wait_restore_default_operations( the_thread ); } the_thread->Wait.return_code = return_code; @@ -252,7 +234,7 @@ Thread_Control *_Thread_queue_Dequeue( first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT ); if ( first ) { the_thread = THREAD_RBTREE_NODE_TO_THREAD( first ); - _Thread_Priority_restore_default_change_handler( the_thread ); + _Thread_Wait_restore_default_operations( the_thread ); } } diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c new file mode 100644 index 0000000000..561480130a --- /dev/null +++ b/cpukit/score/src/threadqops.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +static void _Thread_queue_Do_nothing_priority_change( + Thread_Control *the_thread, + Priority_Control new_priority, + Thread_queue_Control *queue +) +{ + /* Do nothing */ +} + +static void _Thread_queue_Priority_priority_change( + Thread_Control *the_thread, + Priority_Control new_priority, + Thread_queue_Control *queue +) +{ + _RBTree_Extract( &queue->Queues.Priority, &the_thread->RBNode ); + _RBTree_Insert( + &queue->Queues.Priority, + &the_thread->RBNode, + _Thread_queue_Compare_priority, + false + ); +} + +const Thread_queue_Operations _Thread_queue_Operations_default = { + .priority_change = _Thread_queue_Do_nothing_priority_change +}; + +const Thread_queue_Operations _Thread_queue_Operations_FIFO = { + .priority_change = _Thread_queue_Do_nothing_priority_change +}; + +const Thread_queue_Operations _Thread_queue_Operations_priority = { + .priority_change = _Thread_queue_Priority_priority_change +}; diff --git a/testsuites/sptests/spintrcritical23/init.c b/testsuites/sptests/spintrcritical23/init.c index 8536489f5d..89fea25a12 100644 --- a/testsuites/sptests/spintrcritical23/init.c +++ b/testsuites/sptests/spintrcritical23/init.c @@ -70,7 +70,7 @@ static void change_priority(rtems_id timer, void *arg) rtems_interrupt_lock_acquire(&ctx->lock, &lock_context); if ( - ctx->priority_generation != ctx->tcb->Priority.generation + ctx->priority_generation != ctx->tcb->priority_generation && scheduler_node_unchanged(ctx) ) { rtems_task_priority priority_interrupt; @@ -113,7 +113,7 @@ static bool test_body(void *arg) priority_interrupt = 1 + (priority_task + 1) % 3; ctx->priority_task = priority_task; ctx->priority_interrupt = priority_interrupt; - ctx->priority_generation = ctx->tcb->Priority.generation; + ctx->priority_generation = ctx->tcb->priority_generation; memcpy( &ctx->scheduler_node, ctx->tcb->Scheduler.node, -- cgit v1.2.3 From 383cf42217d05a9cf19c6d081d50f92b2262a308 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 22 Apr 2015 11:15:46 +0200 Subject: score: More thread queue operations Move thread queue discipline specific operations into Thread_queue_Operations. Use a separate node in the thread control block for the thread queue to make it independent of the scheduler data structures. Update #2273. --- cpukit/posix/src/killinfo.c | 2 +- cpukit/score/include/rtems/score/thread.h | 19 +++- cpukit/score/include/rtems/score/threadimpl.h | 5 +- cpukit/score/include/rtems/score/threadq.h | 106 ++++++++++++++++++- cpukit/score/src/thread.c | 1 - cpukit/score/src/threadq.c | 15 +-- cpukit/score/src/threadqenqueue.c | 58 ++--------- cpukit/score/src/threadqfirst.c | 19 +--- cpukit/score/src/threadqops.c | 143 ++++++++++++++++++++++++-- cpukit/score/src/threadtimeout.c | 6 ++ 10 files changed, 282 insertions(+), 92 deletions(-) diff --git a/cpukit/posix/src/killinfo.c b/cpukit/posix/src/killinfo.c index 5d3dded53f..c8c59d6096 100644 --- a/cpukit/posix/src/killinfo.c +++ b/cpukit/posix/src/killinfo.c @@ -146,7 +146,7 @@ int killinfo( !_Chain_Is_tail( the_chain, the_node ) ; the_node = the_node->next ) { - the_thread = (Thread_Control *)the_node; + the_thread = THREAD_CHAIN_NODE_TO_THREAD( the_node ); api = the_thread->API_Extensions[ THREAD_API_POSIX ]; #if defined(DEBUG_SIGNAL_PROCESSING) diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index bce6f5643e..b6662e49af 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -286,6 +286,21 @@ typedef unsigned int Thread_Wait_flags; * blocked and to return information to it. */ typedef struct { + /** + * @brief Node for thread queues. + */ + union { + /** + * @brief A node for chains. + */ + Chain_Node Chain; + + /** + * @brief A node for red-black trees. + */ + RBTree_Node RBTree; + } Node; + /** This field is the Id of the object this thread is waiting upon. */ Objects_Id id; /** This field is used to return an integer while when blocked. */ @@ -349,8 +364,6 @@ typedef struct { typedef struct { /** This field is the object management structure for each proxy. */ Objects_Control Object; - /** This field is used to enqueue the thread on RBTrees. */ - RBTree_Node RBNode; /** This field is the current execution state of this proxy. */ States_Control current_state; /** This field is the current priority state of this proxy. */ @@ -638,8 +651,6 @@ typedef struct { struct Thread_Control_struct { /** This field is the object management structure for each thread. */ Objects_Control Object; - /** This field is used to enqueue the thread on RBTrees. */ - RBTree_Node RBNode; /** This field is the current execution state of this thread. */ States_Control current_state; /** This field is the current priority state of this thread. */ diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 953b88b925..b8c235c846 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -78,8 +78,11 @@ SCORE_EXTERN Thread_Control *_Thread_Allocated_fp; SCORE_EXTERN struct _reent **_Thread_libc_reent; #endif +#define THREAD_CHAIN_NODE_TO_THREAD( node ) \ + RTEMS_CONTAINER_OF( node, Thread_Control, Wait.Node.Chain ) + #define THREAD_RBTREE_NODE_TO_THREAD( node ) \ - RTEMS_CONTAINER_OF( node, Thread_Control, RBNode ) + RTEMS_CONTAINER_OF( node, Thread_Control, Wait.Node.RBTree ) #if defined(RTEMS_SMP) #define THREAD_RESOURCE_NODE_TO_THREAD( node ) \ diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index c483b87620..59781ac73c 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -49,14 +49,81 @@ typedef struct Thread_queue_Control Thread_queue_Control; * * @param[in] the_thread The thread. * @param[in] new_priority The new priority value. - * @param[in] queue The thread queue. + * @param[in] the_thread_queue The thread queue. * * @see Thread_queue_Operations. */ typedef void ( *Thread_queue_Priority_change_operation )( Thread_Control *the_thread, Priority_Control new_priority, - Thread_queue_Control *queue + Thread_queue_Control *the_thread_queue +); + +/** + * @brief Thread queue initialize operation. + * + * @param[in] the_thread_queue The thread queue. + * + * @see _Thread_Wait_set_operations(). + */ +typedef void ( *Thread_queue_Initialize_operation )( + Thread_queue_Control *the_thread_queue +); + +/** + * @brief Thread queue enqueue operation. + * + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to enqueue on the queue. + * + * @see _Thread_Wait_set_operations(). + */ +typedef void ( *Thread_queue_Enqueue_operation )( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +); + +/** + * @brief Thread queue dequeue operation. + * + * @param[in] the_thread_queue The thread queue. + * + * @retval NULL No thread is present on the thread queue. + * @retval first The first thread of the thread queue according to the insert + * order. This thread is no longer on the thread queue. + * + * @see _Thread_Wait_set_operations(). + */ +typedef Thread_Control *( *Thread_queue_Dequeue_operation )( + Thread_queue_Control *the_thread_queue +); + +/** + * @brief Thread queue extract operation. + * + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract from the thread queue. + * + * @see _Thread_Wait_set_operations(). + */ +typedef void ( *Thread_queue_Extract_operation )( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +); + +/** + * @brief Thread queue first operation. + * + * @param[in] the_thread_queue The thread queue. + * + * @retval NULL No thread is present on the thread queue. + * @retval first The first thread of the thread queue according to the insert + * order. This thread remains on the thread queue. + * + * @see _Thread_Wait_set_operations(). + */ +typedef Thread_Control *( *Thread_queue_First_operation )( + Thread_queue_Control *the_thread_queue ); /** @@ -76,6 +143,39 @@ typedef struct { * to be done during a priority change. */ Thread_queue_Priority_change_operation priority_change; + + /** + * @brief Thread queue initialize operation. + * + * Called by object initialization routines. + */ + Thread_queue_Initialize_operation initialize; + + /** + * @brief Thread queue enqueue operation. + * + * Called by object routines to enqueue the thread. + */ + Thread_queue_Enqueue_operation enqueue; + + /** + * @brief Thread queue dequeue operation. + * + * Called by object routines to dequeue the first waiting thread if present. + */ + Thread_queue_Dequeue_operation dequeue; + + /** + * @brief Thread queue extract operation. + * + * Called by object routines to extract a thread from a thread queue. + */ + Thread_queue_Extract_operation extract; + + /** + * @brief Thread queue first operation. + */ + Thread_queue_First_operation first; } Thread_queue_Operations; /** @@ -120,8 +220,6 @@ struct Thread_queue_Control { /** This field is used to manage the critical section. */ Thread_blocking_operation_States sync_state; - /** This field indicates the thread queue's blocking discipline. */ - Thread_queue_Disciplines discipline; /** This is the status value returned to threads which timeout while * waiting on this thread queue. */ diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c index f4c53079d5..8a34ced684 100644 --- a/cpukit/score/src/thread.c +++ b/cpukit/score/src/thread.c @@ -28,7 +28,6 @@ ) THREAD_OFFSET_ASSERT( Object ); -THREAD_OFFSET_ASSERT( RBNode ); THREAD_OFFSET_ASSERT( current_state ); THREAD_OFFSET_ASSERT( current_priority ); THREAD_OFFSET_ASSERT( real_priority ); diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c index 47c294e968..61832c19a2 100644 --- a/cpukit/score/src/threadq.c +++ b/cpukit/score/src/threadq.c @@ -19,9 +19,7 @@ #endif #include -#include #include -#include #include RBTree_Compare_result _Thread_queue_Compare_priority( @@ -51,15 +49,20 @@ void _Thread_queue_Initialize( uint32_t timeout_status ) { - the_thread_queue->discipline = the_discipline; + const Thread_queue_Operations *operations; + the_thread_queue->timeout_status = timeout_status; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; _ISR_lock_Initialize( &the_thread_queue->Lock, "Thread Queue" ); if ( the_discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { - _RBTree_Initialize_empty( &the_thread_queue->Queues.Priority ); - } else { /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ - _Chain_Initialize_empty( &the_thread_queue->Queues.Fifo ); + operations = &_Thread_queue_Operations_priority; + } else { + _Assert( the_discipline == THREAD_QUEUE_DISCIPLINE_FIFO ); + operations = &_Thread_queue_Operations_FIFO; } + + the_thread_queue->operations = operations; + ( *operations->initialize )( the_thread_queue ); } diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 6cc731e282..be08ffcbf1 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -47,6 +46,7 @@ static void _Thread_blocking_operation_Finalize( * The thread is not waiting on anything after this completes. */ _Thread_Wait_set_queue( the_thread, NULL ); + _Thread_Wait_restore_default_operations( the_thread ); _Thread_Lock_restore_default( the_thread ); @@ -127,28 +127,14 @@ void _Thread_queue_Enqueue_critical( the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { - /* - * Invoke the discipline specific enqueue method. - */ - if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { - _Chain_Append_unprotected( - &the_thread_queue->Queues.Fifo, - &the_thread->Object.Node - ); - } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ - _Thread_Wait_set_operations( - the_thread, - &_Thread_queue_Operations_priority - ); - _RBTree_Insert( - &the_thread_queue->Queues.Priority, - &the_thread->RBNode, - _Thread_queue_Compare_priority, - false - ); - } + const Thread_queue_Operations *operations; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + + operations = the_thread_queue->operations; + _Thread_Wait_set_operations( the_thread, operations ); + ( *operations->enqueue )( the_thread_queue, the_thread ); + _Thread_queue_Release( the_thread_queue, lock_context ); } else { /* Cancel a blocking operation due to ISR */ @@ -181,15 +167,7 @@ void _Thread_queue_Extract_with_return_code( _SMP_Assert( lock == &the_thread_queue->Lock ); - if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { - _Chain_Extract_unprotected( &the_thread->Object.Node ); - } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ - _RBTree_Extract( - &the_thread->Wait.queue->Queues.Priority, - &the_thread->RBNode - ); - _Thread_Wait_restore_default_operations( the_thread ); - } + ( *the_thread_queue->operations->extract )( the_thread_queue, the_thread ); the_thread->Wait.return_code = return_code; @@ -217,27 +195,9 @@ Thread_Control *_Thread_queue_Dequeue( ISR_lock_Context lock_context; Thread_blocking_operation_States sync_state; - the_thread = NULL; _Thread_queue_Acquire( the_thread_queue, &lock_context ); - /* - * Invoke the discipline specific dequeue method. - */ - if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { - if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) { - the_thread = (Thread_Control *) - _Chain_Get_first_unprotected( &the_thread_queue->Queues.Fifo ); - } - } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ - RBTree_Node *first; - - first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT ); - if ( first ) { - the_thread = THREAD_RBTREE_NODE_TO_THREAD( first ); - _Thread_Wait_restore_default_operations( the_thread ); - } - } - + the_thread = ( *the_thread_queue->operations->dequeue )( the_thread_queue ); if ( the_thread == NULL ) { /* * We did not find a thread to unblock in the queue. Maybe the executing diff --git a/cpukit/score/src/threadqfirst.c b/cpukit/score/src/threadqfirst.c index f43b9abbd0..553b28bf62 100644 --- a/cpukit/score/src/threadqfirst.c +++ b/cpukit/score/src/threadqfirst.c @@ -19,29 +19,12 @@ #endif #include -#include -#include Thread_Control *_Thread_queue_First_locked( Thread_queue_Control *the_thread_queue ) { - Thread_Control *thread; - - thread = NULL; - - if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { - if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) - thread = (Thread_Control *) _Chain_First(&the_thread_queue->Queues.Fifo); - } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ - RBTree_Node *first; - - first = _RBTree_First( &the_thread_queue->Queues.Priority, RBT_LEFT ); - if ( first ) - thread = THREAD_RBTREE_NODE_TO_THREAD( first ); - } - - return thread; + return ( *the_thread_queue->operations->first )( the_thread_queue ); } Thread_Control *_Thread_queue_First( diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c index 561480130a..9958ed667c 100644 --- a/cpukit/score/src/threadqops.c +++ b/cpukit/score/src/threadqops.c @@ -17,40 +17,167 @@ #endif #include +#include #include static void _Thread_queue_Do_nothing_priority_change( Thread_Control *the_thread, Priority_Control new_priority, - Thread_queue_Control *queue + Thread_queue_Control *the_thread_queue ) { /* Do nothing */ } +static void _Thread_queue_Do_nothing_extract( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + /* Do nothing */ +} + +static void _Thread_queue_FIFO_initialize( + Thread_queue_Control *the_thread_queue +) +{ + _Chain_Initialize_empty( &the_thread_queue->Queues.Fifo ); +} + +static void _Thread_queue_FIFO_enqueue( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + _Chain_Append_unprotected( + &the_thread_queue->Queues.Fifo, + &the_thread->Wait.Node.Chain + ); +} + +static Thread_Control *_Thread_queue_FIFO_dequeue( + Thread_queue_Control *the_thread_queue +) +{ + Chain_Control *fifo = &the_thread_queue->Queues.Fifo; + + return _Chain_Is_empty( fifo ) ? + NULL : THREAD_CHAIN_NODE_TO_THREAD( _Chain_Get_first_unprotected( fifo ) ); +} + +static void _Thread_queue_FIFO_extract( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + _Chain_Extract_unprotected( &the_thread->Wait.Node.Chain ); +} + +static Thread_Control *_Thread_queue_FIFO_first( + Thread_queue_Control *the_thread_queue +) +{ + Chain_Control *fifo = &the_thread_queue->Queues.Fifo; + + return _Chain_Is_empty( fifo ) ? + NULL : THREAD_CHAIN_NODE_TO_THREAD( _Chain_First( fifo ) ); +} + static void _Thread_queue_Priority_priority_change( Thread_Control *the_thread, Priority_Control new_priority, - Thread_queue_Control *queue + Thread_queue_Control *the_thread_queue +) +{ + _RBTree_Extract( + &the_thread_queue->Queues.Priority, + &the_thread->Wait.Node.RBTree + ); + _RBTree_Insert( + &the_thread_queue->Queues.Priority, + &the_thread->Wait.Node.RBTree, + _Thread_queue_Compare_priority, + false + ); +} + +static void _Thread_queue_Priority_initialize( + Thread_queue_Control *the_thread_queue +) +{ + _RBTree_Initialize_empty( &the_thread_queue->Queues.Priority ); +} + +static void _Thread_queue_Priority_enqueue( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread ) { - _RBTree_Extract( &queue->Queues.Priority, &the_thread->RBNode ); _RBTree_Insert( - &queue->Queues.Priority, - &the_thread->RBNode, + &the_thread_queue->Queues.Priority, + &the_thread->Wait.Node.RBTree, _Thread_queue_Compare_priority, false ); } +static Thread_Control *_Thread_queue_Priority_dequeue( + Thread_queue_Control *the_thread_queue +) +{ + RBTree_Node *first; + + first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT ); + + return first != NULL ? THREAD_RBTREE_NODE_TO_THREAD( first ) : NULL; +} + +static void _Thread_queue_Priority_extract( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + _RBTree_Extract( + &the_thread_queue->Queues.Priority, + &the_thread->Wait.Node.RBTree + ); +} + +static Thread_Control *_Thread_queue_Priority_first( + Thread_queue_Control *the_thread_queue +) +{ + RBTree_Node *first; + + first = _RBTree_First( &the_thread_queue->Queues.Priority, RBT_LEFT ); + + return first != NULL ? THREAD_RBTREE_NODE_TO_THREAD( first ) : NULL; +} + const Thread_queue_Operations _Thread_queue_Operations_default = { - .priority_change = _Thread_queue_Do_nothing_priority_change + .priority_change = _Thread_queue_Do_nothing_priority_change, + .extract = _Thread_queue_Do_nothing_extract + /* + * The default operations are only used in _Thread_Change_priority() and + * _Thread_Timeout() and don't have a thread queue associated with them, so + * the enqueue and first operations are superfluous. + */ }; const Thread_queue_Operations _Thread_queue_Operations_FIFO = { - .priority_change = _Thread_queue_Do_nothing_priority_change + .priority_change = _Thread_queue_Do_nothing_priority_change, + .initialize = _Thread_queue_FIFO_initialize, + .enqueue = _Thread_queue_FIFO_enqueue, + .dequeue = _Thread_queue_FIFO_dequeue, + .extract = _Thread_queue_FIFO_extract, + .first = _Thread_queue_FIFO_first }; const Thread_queue_Operations _Thread_queue_Operations_priority = { - .priority_change = _Thread_queue_Priority_priority_change + .priority_change = _Thread_queue_Priority_priority_change, + .initialize = _Thread_queue_Priority_initialize, + .enqueue = _Thread_queue_Priority_enqueue, + .dequeue = _Thread_queue_Priority_dequeue, + .extract = _Thread_queue_Priority_extract, + .first = _Thread_queue_Priority_first }; diff --git a/cpukit/score/src/threadtimeout.c b/cpukit/score/src/threadtimeout.c index b6ce2d7362..300beb5219 100644 --- a/cpukit/score/src/threadtimeout.c +++ b/cpukit/score/src/threadtimeout.c @@ -24,6 +24,12 @@ static void _Thread_Do_timeout( Thread_Control *the_thread ) { the_thread->Wait.return_code = the_thread->Wait.timeout_code; + ( *the_thread->Wait.operations->extract )( + the_thread->Wait.queue, + the_thread + ); + _Thread_Wait_set_queue( the_thread, NULL ); + _Thread_Wait_restore_default_operations( the_thread ); _Thread_Lock_restore_default( the_thread ); } -- cgit v1.2.3 From cc366ec8c9ecaab838a745175a0d53a7a5db437e Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 24 Apr 2015 12:02:20 +0200 Subject: score: New thread queue implementation Use thread wait flags for synchronization. The enqueue operation is now part of the initial critical section. This is the key change and enables fine grained locking on SMP for objects using a thread queue like semaphores and message queues. Update #2273. --- cpukit/score/Makefile.am | 3 +- cpukit/score/include/rtems/score/threadq.h | 25 --- cpukit/score/include/rtems/score/threadqimpl.h | 189 ++++++++++++++------ cpukit/score/include/rtems/score/threadsync.h | 60 ------- cpukit/score/preinstall.am | 4 - cpukit/score/src/threadq.c | 1 - cpukit/score/src/threadqenqueue.c | 232 +++++++++++-------------- cpukit/score/src/threadqfirst.c | 7 - cpukit/score/src/threadqflush.c | 24 ++- cpukit/score/src/threadqops.c | 23 --- cpukit/score/src/threadqprocesstimeout.c | 80 --------- cpukit/score/src/threadqtimeout.c | 44 ----- cpukit/score/src/threadtimeout.c | 6 + testsuites/sptests/spintrcritical01/init.c | 38 ++-- testsuites/sptests/spintrcritical09/init.c | 28 ++- testsuites/sptests/spintrcritical16/init.c | 37 ++-- testsuites/sptests/spintrcritical20/init.c | 10 +- testsuites/sptests/spintrcritical22/init.c | 8 +- 18 files changed, 320 insertions(+), 499 deletions(-) delete mode 100644 cpukit/score/include/rtems/score/threadsync.h delete mode 100644 cpukit/score/src/threadqprocesstimeout.c delete mode 100644 cpukit/score/src/threadqtimeout.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 18becdb300..19d3237607 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -82,7 +82,6 @@ include_rtems_score_HEADERS += include/rtems/score/threadimpl.h include_rtems_score_HEADERS += include/rtems/score/threaddispatch.h include_rtems_score_HEADERS += include/rtems/score/threadq.h include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h -include_rtems_score_HEADERS += include/rtems/score/threadsync.h include_rtems_score_HEADERS += include/rtems/score/timespec.h include_rtems_score_HEADERS += include/rtems/score/timestamp.h include_rtems_score_HEADERS += include/rtems/score/timestamp64.h @@ -301,7 +300,7 @@ endif libscore_a_SOURCES += src/threadq.c \ src/threadqenqueue.c \ src/threadqextractwithproxy.c src/threadqfirst.c \ - src/threadqflush.c src/threadqprocesstimeout.c src/threadqtimeout.c + src/threadqflush.c libscore_a_SOURCES += src/threadqops.c ## TIMESPEC_C_FILES diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index 59781ac73c..b89198608a 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -25,7 +25,6 @@ #include #include #include -#include #ifdef __cplusplus extern "C" { @@ -83,21 +82,6 @@ typedef void ( *Thread_queue_Enqueue_operation )( Thread_Control *the_thread ); -/** - * @brief Thread queue dequeue operation. - * - * @param[in] the_thread_queue The thread queue. - * - * @retval NULL No thread is present on the thread queue. - * @retval first The first thread of the thread queue according to the insert - * order. This thread is no longer on the thread queue. - * - * @see _Thread_Wait_set_operations(). - */ -typedef Thread_Control *( *Thread_queue_Dequeue_operation )( - Thread_queue_Control *the_thread_queue -); - /** * @brief Thread queue extract operation. * @@ -158,13 +142,6 @@ typedef struct { */ Thread_queue_Enqueue_operation enqueue; - /** - * @brief Thread queue dequeue operation. - * - * Called by object routines to dequeue the first waiting thread if present. - */ - Thread_queue_Dequeue_operation dequeue; - /** * @brief Thread queue extract operation. * @@ -218,8 +195,6 @@ struct Thread_queue_Control { */ ISR_LOCK_MEMBER( Lock ) - /** This field is used to manage the critical section. */ - Thread_blocking_operation_States sync_state; /** This is the status value returned to threads which timeout while * waiting on this thread queue. */ diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 04e67309b2..9893aae8af 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -80,13 +80,54 @@ Thread_Control *_Thread_queue_Dequeue( ); /** - * @brief Blocks a thread and places it on a thread queue. + * @brief Blocks the thread and places it on the thread queue. * - * This routine blocks a thread, places it on a thread queue, and optionally - * starts a watchdog in case the timeout interval is not WATCHDOG_NO_TIMEOUT. + * This enqueues the thread on the thread queue, blocks the thread, and + * optionally starts the thread timer in case the timeout interval is not + * WATCHDOG_NO_TIMEOUT. * * The caller must be the owner of the thread queue lock. This function will * release the thread queue lock and register it as the new thread lock. + * Thread dispatching is disabled before the thread queue lock is released. + * Thread dispatching is enabled once the sequence to block the thread is + * complete. The operation to enqueue the thread on the queue is protected by + * the thread queue lock. This makes it possible to use the thread queue lock + * to protect the state of objects embedding the thread queue and directly + * enter _Thread_queue_Enqueue_critical() in case the thread must block. + * + * @code + * #include + * #include + * + * typedef struct { + * Thread_queue_Control Queue; + * Thread_Control *owner; + * } Mutex; + * + * void _Mutex_Obtain( Mutex *mutex ) + * { + * ISR_lock_Context lock_context; + * Thread_Control *executing; + * + * _Thread_queue_Acquire( &mutex->Queue, &lock_context ); + * + * executing = _Thread_Executing; + * + * if ( mutex->owner == NULL ) { + * mutex->owner = executing; + * _Thread_queue_Release( &mutex->Queue, &lock_context ); + * } else { + * _Thread_queue_Enqueue_critical( + * &mutex->Queue, + * executing, + * STATES_WAITING_FOR_MUTEX, + * WATCHDOG_NO_TIMEOUT, + * 0, + * &lock_context + * ); + * } + * } + * @endcode * * @param[in] the_thread_queue The thread queue. * @param[in] the_thread The thread to enqueue. @@ -103,6 +144,10 @@ void _Thread_queue_Enqueue_critical( ISR_lock_Context *lock_context ); +/** + * @brief Acquires the thread queue lock and calls + * _Thread_queue_Enqueue_critical(). + */ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, @@ -123,33 +168,97 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( } /** - * @brief Extracts thread from thread queue. + * @brief Extracts the thread from the thread queue, restores the default wait + * operations and restores the default thread lock. * - * This routine removes @a the_thread its thread queue - * and cancels any timeouts associated with this blocking. + * The caller must be the owner of the thread queue lock. The thread queue + * lock is not released. * - * @param[in] the_thread is the pointer to a thread control block that - * is to be removed + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract. */ -void _Thread_queue_Extract( Thread_Control *the_thread ); +void _Thread_queue_Extract_locked( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +); + +/** + * @brief Unblocks the thread which was on the thread queue before. + * + * The caller must be the owner of the thread queue lock. This function will + * release the thread queue lock. Thread dispatching is disabled before the + * thread queue lock is released and an unblock is necessary. Thread + * dispatching is enabled once the sequence to unblock the thread is complete. + * + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract. + * @param[in] lock_context The lock context of the lock acquire. + */ +void _Thread_queue_Unblock_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context +); + +/** + * @brief Extracts the thread from the thread queue and unblocks it. + * + * The caller must be the owner of the thread queue lock. This function will + * release the thread queue lock and restore the default thread lock. Thread + * dispatching is disabled before the thread queue lock is released and an + * unblock is necessary. Thread dispatching is enabled once the sequence to + * unblock the thread is complete. This makes it possible to use the thread + * queue lock to protect the state of objects embedding the thread queue and + * directly enter _Thread_queue_Extract_critical() to finalize an operation in + * case a waiting thread exists. + * + * @code + * #include + * + * typedef struct { + * Thread_queue_Control Queue; + * Thread_Control *owner; + * } Mutex; + * + * void _Mutex_Release( Mutex *mutex ) + * { + * ISR_lock_Context lock_context; + * Thread_Control *first; + * + * _Thread_queue_Acquire( &mutex->Queue, &lock_context ); + * + * first = _Thread_queue_First_locked( &mutex->Queue ); + * mutex->owner = first; + * + * if ( first != NULL ) { + * _Thread_queue_Extract_critical( + * &mutex->Queue, + * first, + * &lock_context + * ); + * } + * @endcode + * + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract. + * @param[in] lock_context The lock context of the lock acquire. + */ +void _Thread_queue_Extract_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context +); /** - * @brief Extracts thread from thread queue (w/return code). + * @brief Extracts thread from thread queue. * * This routine removes @a the_thread its thread queue * and cancels any timeouts associated with this blocking. * * @param[in] the_thread is the pointer to a thread control block that * is to be removed - * @param[in] return_code specifies the status to be returned. - * - * - INTERRUPT LATENCY: - * + single case */ -void _Thread_queue_Extract_with_return_code( - Thread_Control *the_thread, - uint32_t return_code -); +void _Thread_queue_Extract( Thread_Control *the_thread ); /** * @brief Extracts the_thread from the_thread_queue. @@ -164,9 +273,10 @@ void _Thread_queue_Extract_with_proxy( /** * @brief Returns the first thread on the thread queue if it exists, otherwise - * @c NULL (locked). + * @c NULL. * - * The caller must be the owner of the thread queue lock. + * The caller must be the owner of the thread queue lock. The thread queue + * lock is not released. * * @param[in] the_thread_queue The thread queue. * @@ -174,9 +284,12 @@ void _Thread_queue_Extract_with_proxy( * @retval first The first thread on the thread queue according to the enqueue * order. */ -Thread_Control *_Thread_queue_First_locked( +RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked( Thread_queue_Control *the_thread_queue -); +) +{ + return ( *the_thread_queue->operations->first )( the_thread_queue ); +} /** * @brief Returns the first thread on the thread queue if it exists, otherwise @@ -234,38 +347,6 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy( _ISR_lock_Destroy( &the_thread_queue->Lock ); } -/** - * @brief Thread queue timeout. - * - * This routine is invoked when a task's request has not - * been satisfied after the timeout interval specified to - * enqueue. The task represented by ID will be unblocked and - * its status code will be set in it's control block to indicate - * that a timeout has occurred. - * - * @param[in] id thread id - */ -void _Thread_queue_Timeout( - Objects_Id id, - void *ignored -); - -/** - * @brief Process thread queue timeout. - * - * This is a shared helper routine which makes it easier to have multiple - * object class specific timeout routines. - * - * @param[in] the_thread is the thread to extract - * - * @note This method assumes thread dispatching is disabled - * and is expected to be called via the processing of - * a clock tick. - */ -void _Thread_queue_Process_timeout( - Thread_Control *the_thread -); - /** * @brief Compare two thread's priority for RBTree Insertion. * diff --git a/cpukit/score/include/rtems/score/threadsync.h b/cpukit/score/include/rtems/score/threadsync.h deleted file mode 100644 index fa7aeeb003..0000000000 --- a/cpukit/score/include/rtems/score/threadsync.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file rtems/score/threadsync.h - * - * @brief Synchronize Thread Blocking Operations with Actions in an ISR - * - * This include file contains all constants and structures associated - * with synchronizing a thread blocking operation with potential - * actions in an ISR. - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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. - */ - -#ifndef _RTEMS_SCORE_THREAD_SYNC_H -#define _RTEMS_SCORE_THREAD_SYNC_H - -/** - * @defgroup ScoreThreadSync Thread Blocking Operation Synchronization Handler - * - * @ingroup Score - * - * This handler encapsulates functionality related to the management of - * synchronization critical sections during blocking operations. - */ -/**@{*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The following enumerated types indicate what happened while the thread - * blocking was in the synchronization window. - */ -typedef enum { - THREAD_BLOCKING_OPERATION_SYNCHRONIZED, - THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED, - THREAD_BLOCKING_OPERATION_TIMEOUT, - THREAD_BLOCKING_OPERATION_SATISFIED -} Thread_blocking_operation_States; - -/* - * Operations require a thread pointer so they are prototyped - * in thread.h - */ - -#ifdef __cplusplus -} -#endif - -/**@}*/ - -#endif -/* end of include file */ diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 920c0d9aeb..62e15720f4 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -311,10 +311,6 @@ $(PROJECT_INCLUDE)/rtems/score/threadqimpl.h: include/rtems/score/threadqimpl.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/threadqimpl.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/threadqimpl.h -$(PROJECT_INCLUDE)/rtems/score/threadsync.h: include/rtems/score/threadsync.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/threadsync.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/threadsync.h - $(PROJECT_INCLUDE)/rtems/score/timespec.h: include/rtems/score/timespec.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timespec.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timespec.h diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c index 61832c19a2..cdb99498fe 100644 --- a/cpukit/score/src/threadq.c +++ b/cpukit/score/src/threadq.c @@ -52,7 +52,6 @@ void _Thread_queue_Initialize( const Thread_queue_Operations *operations; the_thread_queue->timeout_status = timeout_status; - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; _ISR_lock_Initialize( &the_thread_queue->Lock, "Thread Queue" ); diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index be08ffcbf1..d02f2ee073 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -20,58 +20,28 @@ #include #include +#include #include #include -/** - * @brief Finalize a blocking operation. - * - * This method is used to finalize a blocking operation that was - * satisfied. It may be used with thread queues or any other synchronization - * object that uses the blocking states and watchdog times for timeout. - * - * This method will restore the previous ISR disable level during the cancel - * operation. Thus it is an implicit _ISR_Enable(). - * - * @param[in] the_thread is the thread whose blocking is canceled - * @param[in] lock_context is the previous ISR disable level - */ -static void _Thread_blocking_operation_Finalize( - Thread_queue_Control *the_thread_queue, - Thread_Control *the_thread, - ISR_lock_Context *lock_context -) -{ - /* - * The thread is not waiting on anything after this completes. - */ - _Thread_Wait_set_queue( the_thread, NULL ); - _Thread_Wait_restore_default_operations( the_thread ); +#define THREAD_QUEUE_INTEND_TO_BLOCK \ + (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK) - _Thread_Lock_restore_default( the_thread ); +#define THREAD_QUEUE_BLOCKED \ + (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_BLOCKED) - /* - * If the sync state is timed out, this is very likely not needed. - * But better safe than sorry when it comes to critical sections. - */ - if ( _Watchdog_Is_active( &the_thread->Timer ) ) { - _Watchdog_Deactivate( &the_thread->Timer ); - _Thread_queue_Release( the_thread_queue, lock_context ); - _Watchdog_Remove_ticks( &the_thread->Timer ); - } else - _Thread_queue_Release( the_thread_queue, lock_context ); - - /* - * Global objects with thread queue's should not be operated on from an - * ISR. But the sync code still must allow short timeouts to be processed - * correctly. - */ +#define THREAD_QUEUE_READY_AGAIN \ + (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN) +static void _Thread_queue_Unblock( Thread_Control *the_thread ) +{ + _Watchdog_Remove_ticks( &the_thread->Timer ); _Thread_Unblock( the_thread ); #if defined(RTEMS_MULTIPROCESSING) - if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { _Thread_MP_Free_proxy( the_thread ); + } #endif } @@ -83,13 +53,20 @@ void _Thread_queue_Enqueue_critical( ISR_lock_Context *lock_context ) { - Thread_blocking_operation_States sync_state; + const Thread_queue_Operations *operations; + Per_CPU_Control *cpu_self; + bool success; _Thread_Lock_set( the_thread, &the_thread_queue->Lock ); - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + operations = the_thread_queue->operations; _Thread_Wait_set_queue( the_thread, the_thread_queue ); + _Thread_Wait_set_operations( the_thread, operations ); + + ( *operations->enqueue )( the_thread_queue, the_thread ); + _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK ); + cpu_self = _Thread_Dispatch_disable_critical(); _Thread_queue_Release( the_thread_queue, lock_context ); #if defined(RTEMS_MULTIPROCESSING) @@ -105,121 +82,120 @@ void _Thread_queue_Enqueue_critical( /* * If the thread wants to timeout, then schedule its timer. */ - if ( timeout ) { - _Watchdog_Initialize( - &the_thread->Timer, - _Thread_queue_Timeout, - the_thread->Object.id, - NULL + if ( timeout != WATCHDOG_NO_TIMEOUT ) { + _Thread_Wait_set_timeout_code( + the_thread, + the_thread_queue->timeout_status ); - + _Watchdog_Initialize( &the_thread->Timer, _Thread_Timeout, 0, the_thread ); _Watchdog_Insert_ticks( &the_thread->Timer, timeout ); } - /* - * Now initiate the enqueuing and checking if the blocking operation - * should be completed or the thread has had its blocking condition - * satisfied before we got here. - */ - _Thread_queue_Acquire( the_thread_queue, lock_context ); + success = _Thread_Wait_flags_try_change( + the_thread, + THREAD_QUEUE_INTEND_TO_BLOCK, + THREAD_QUEUE_BLOCKED + ); + if ( !success ) { + _Thread_queue_Unblock( the_thread ); + } - sync_state = the_thread_queue->sync_state; - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + _Thread_Dispatch_enable( cpu_self ); +} - if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { - const Thread_queue_Operations *operations; +void _Thread_queue_Extract_locked( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + ( *the_thread_queue->operations->extract )( the_thread_queue, the_thread ); - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + _Thread_Wait_set_queue( the_thread, NULL ); + _Thread_Wait_restore_default_operations( the_thread ); + _Thread_Lock_restore_default( the_thread ); +} - operations = the_thread_queue->operations; - _Thread_Wait_set_operations( the_thread, operations ); - ( *operations->enqueue )( the_thread_queue, the_thread ); +void _Thread_queue_Unblock_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context +) +{ + bool success; + bool unblock; - _Thread_queue_Release( the_thread_queue, lock_context ); + success = _Thread_Wait_flags_try_change_critical( + the_thread, + THREAD_QUEUE_INTEND_TO_BLOCK, + THREAD_QUEUE_READY_AGAIN + ); + if ( success ) { + unblock = false; } else { - /* Cancel a blocking operation due to ISR */ + _Assert( _Thread_Wait_flags_get( the_thread ) == THREAD_QUEUE_BLOCKED ); + _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_READY_AGAIN ); + unblock = true; + } - _Assert( - sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT || - sync_state == THREAD_BLOCKING_OPERATION_SATISFIED - ); + if ( unblock ) { + Per_CPU_Control *cpu_self; - _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, lock_context ); + cpu_self = _Thread_Dispatch_disable_critical(); + _Thread_queue_Release( the_thread_queue, lock_context ); + + _Thread_queue_Unblock( the_thread ); + + _Thread_Dispatch_enable( cpu_self ); + } else { + _Thread_queue_Release( the_thread_queue, lock_context ); } } -void _Thread_queue_Extract_with_return_code( - Thread_Control *the_thread, - uint32_t return_code +void _Thread_queue_Extract_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { - Thread_queue_Control *the_thread_queue; - ISR_lock_Control *lock; + _Thread_queue_Extract_locked( the_thread_queue, the_thread ); + _Thread_queue_Unblock_critical( the_thread_queue, the_thread, lock_context ); +} + +void _Thread_queue_Extract( Thread_Control *the_thread ) +{ ISR_lock_Context lock_context; + ISR_lock_Control *lock; + Thread_queue_Control *the_thread_queue; lock = _Thread_Lock_acquire( the_thread, &lock_context ); the_thread_queue = the_thread->Wait.queue; - if ( the_thread_queue == NULL ) { - _Thread_Lock_release( lock, &lock_context ); - return; - } - - _SMP_Assert( lock == &the_thread_queue->Lock ); - - ( *the_thread_queue->operations->extract )( the_thread_queue, the_thread ); - the_thread->Wait.return_code = return_code; + if ( the_thread_queue != NULL ) { + _SMP_Assert( lock == &the_thread_queue->Lock ); - /* - * We found a thread to unblock. - * - * NOTE: This is invoked with interrupts still disabled. - */ - _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, &lock_context ); -} - -void _Thread_queue_Extract( Thread_Control *the_thread ) -{ - _Thread_queue_Extract_with_return_code( - the_thread, - the_thread->Wait.return_code - ); + _Thread_queue_Extract_critical( the_thread_queue, the_thread, &lock_context ); + } else { + _Thread_Lock_release( lock, &lock_context ); + } } -Thread_Control *_Thread_queue_Dequeue( - Thread_queue_Control *the_thread_queue -) +Thread_Control *_Thread_queue_Dequeue( Thread_queue_Control *the_thread_queue ) { - Thread_Control *the_thread; - ISR_lock_Context lock_context; - Thread_blocking_operation_States sync_state; + ISR_lock_Context lock_context; + Thread_Control *the_thread; _Thread_queue_Acquire( the_thread_queue, &lock_context ); - the_thread = ( *the_thread_queue->operations->dequeue )( the_thread_queue ); - if ( the_thread == NULL ) { - /* - * We did not find a thread to unblock in the queue. Maybe the executing - * thread is about to block on this thread queue. - */ - sync_state = the_thread_queue->sync_state; - if ( (sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT) || - (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) ) { - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SATISFIED; - the_thread = _Thread_Executing; - } else { - _Thread_queue_Release( the_thread_queue, &lock_context ); - return NULL; - } - } + the_thread = _Thread_queue_First_locked( the_thread_queue ); - /* - * We found a thread to unblock. - * - * NOTE: This is invoked with interrupts still disabled. - */ - _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, &lock_context ); + if ( the_thread != NULL ) { + _SMP_Assert( the_thread->Lock.current == &the_thread_queue->Lock ); + + _Thread_queue_Extract_critical( the_thread_queue, the_thread, &lock_context ); + } else { + _Thread_queue_Release( the_thread_queue, &lock_context ); + } return the_thread; } diff --git a/cpukit/score/src/threadqfirst.c b/cpukit/score/src/threadqfirst.c index 553b28bf62..c46f005c3e 100644 --- a/cpukit/score/src/threadqfirst.c +++ b/cpukit/score/src/threadqfirst.c @@ -20,13 +20,6 @@ #include -Thread_Control *_Thread_queue_First_locked( - Thread_queue_Control *the_thread_queue -) -{ - return ( *the_thread_queue->operations->first )( the_thread_queue ); -} - Thread_Control *_Thread_queue_First( Thread_queue_Control *the_thread_queue ) diff --git a/cpukit/score/src/threadqflush.c b/cpukit/score/src/threadqflush.c index 1abe8aca3e..d37b9e8ae7 100644 --- a/cpukit/score/src/threadqflush.c +++ b/cpukit/score/src/threadqflush.c @@ -31,14 +31,30 @@ void _Thread_queue_Flush( uint32_t status ) { - Thread_Control *the_thread; + ISR_lock_Context lock_context; + Thread_Control *the_thread; + + _Thread_queue_Acquire( the_thread_queue, &lock_context ); + + while ( (the_thread = _Thread_queue_First_locked( the_thread_queue ) ) ) { +#if defined(RTEMS_MULTIPROCESSING) + if ( _Objects_Is_local_id( the_thread->Object.id ) ) +#endif + the_thread->Wait.return_code = status; + + _Thread_queue_Extract_critical( + the_thread_queue, + the_thread, + &lock_context + ); - while ( (the_thread = _Thread_queue_Dequeue( the_thread_queue )) ) { #if defined(RTEMS_MULTIPROCESSING) if ( !_Objects_Is_local_id( the_thread->Object.id ) ) ( *remote_extract_callout )( the_thread ); - else #endif - the_thread->Wait.return_code = status; + + _Thread_queue_Acquire( the_thread_queue, &lock_context ); } + + _Thread_queue_Release( the_thread_queue, &lock_context ); } diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c index 9958ed667c..2967a0efc3 100644 --- a/cpukit/score/src/threadqops.c +++ b/cpukit/score/src/threadqops.c @@ -55,16 +55,6 @@ static void _Thread_queue_FIFO_enqueue( ); } -static Thread_Control *_Thread_queue_FIFO_dequeue( - Thread_queue_Control *the_thread_queue -) -{ - Chain_Control *fifo = &the_thread_queue->Queues.Fifo; - - return _Chain_Is_empty( fifo ) ? - NULL : THREAD_CHAIN_NODE_TO_THREAD( _Chain_Get_first_unprotected( fifo ) ); -} - static void _Thread_queue_FIFO_extract( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread @@ -121,17 +111,6 @@ static void _Thread_queue_Priority_enqueue( ); } -static Thread_Control *_Thread_queue_Priority_dequeue( - Thread_queue_Control *the_thread_queue -) -{ - RBTree_Node *first; - - first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT ); - - return first != NULL ? THREAD_RBTREE_NODE_TO_THREAD( first ) : NULL; -} - static void _Thread_queue_Priority_extract( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread @@ -168,7 +147,6 @@ const Thread_queue_Operations _Thread_queue_Operations_FIFO = { .priority_change = _Thread_queue_Do_nothing_priority_change, .initialize = _Thread_queue_FIFO_initialize, .enqueue = _Thread_queue_FIFO_enqueue, - .dequeue = _Thread_queue_FIFO_dequeue, .extract = _Thread_queue_FIFO_extract, .first = _Thread_queue_FIFO_first }; @@ -177,7 +155,6 @@ const Thread_queue_Operations _Thread_queue_Operations_priority = { .priority_change = _Thread_queue_Priority_priority_change, .initialize = _Thread_queue_Priority_initialize, .enqueue = _Thread_queue_Priority_enqueue, - .dequeue = _Thread_queue_Priority_dequeue, .extract = _Thread_queue_Priority_extract, .first = _Thread_queue_Priority_first }; diff --git a/cpukit/score/src/threadqprocesstimeout.c b/cpukit/score/src/threadqprocesstimeout.c deleted file mode 100644 index dbb8f5ce45..0000000000 --- a/cpukit/score/src/threadqprocesstimeout.c +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file - * - * @brief Thread Queue Handler Process Timeout Handler - * @ingroup ScoreThreadQ - */ - -/* - * COPYRIGHT (c) 1989-2008. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -void _Thread_queue_Process_timeout( - Thread_Control *the_thread -) -{ - Thread_queue_Control *the_thread_queue; - ISR_Level level; - - /* - * If the_thread_queue is not synchronized, then it is either - * "nothing happened", "timeout", or "satisfied". If the_thread - * is the executing thread, then it is in the process of blocking - * and it is the thread which is responsible for the synchronization - * process. - * - * If it is not satisfied, then it is "nothing happened" and - * this is the "timeout" transition. After a request is satisfied, - * a timeout is not allowed to occur. - */ - - _ISR_Disable( level ); - the_thread_queue = the_thread->Wait.queue; - if ( the_thread_queue != NULL ) { - if ( the_thread_queue->sync_state != THREAD_BLOCKING_OPERATION_SYNCHRONIZED && - _Thread_Is_executing( the_thread ) ) { - if ( the_thread_queue->sync_state != THREAD_BLOCKING_OPERATION_SATISFIED ) { - the_thread->Wait.return_code = the_thread_queue->timeout_status; - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_TIMEOUT; - } - _ISR_Enable( level ); - } else { - _ISR_Enable( level ); - - /* - * After we enable interrupts here, a lot may happen in the meantime, - * e.g. nested interrupts may release the resource that times out here. - * So we enter _Thread_queue_Extract() speculatively. Inside this - * function we check the actual status under ISR disable protection. - * This ensures that exactly one executing context performs the extract - * operation (other parties may call _Thread_queue_Dequeue()). If this - * context won, then we have a timeout. - * - * We can use the_thread_queue pointer here even if - * the_thread->Wait.queue is already set to NULL since the extract - * operation will only use the thread queue discipline to select the - * right extract operation. The timeout status is set during thread - * queue initialization. - */ - _Thread_queue_Extract_with_return_code( - the_thread, - the_thread_queue->timeout_status - ); - } - } else { - _ISR_Enable( level ); - } -} - diff --git a/cpukit/score/src/threadqtimeout.c b/cpukit/score/src/threadqtimeout.c deleted file mode 100644 index fcacd1c781..0000000000 --- a/cpukit/score/src/threadqtimeout.c +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file - * - * @brief Thread Queue Timeout - * @ingroup ScoreThreadQ - */ - -/* - * COPYRIGHT (c) 1989-2008. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -void _Thread_queue_Timeout( - Objects_Id id, - void *ignored __attribute__((unused)) -) -{ - Thread_Control *the_thread; - Objects_Locations location; - - the_thread = _Thread_Get( id, &location ); - switch ( location ) { - case OBJECTS_ERROR: -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* impossible */ -#endif - break; - case OBJECTS_LOCAL: - _Thread_queue_Process_timeout( the_thread ); - _Objects_Put_without_thread_dispatch( &the_thread->Object ); - break; - } -} diff --git a/cpukit/score/src/threadtimeout.c b/cpukit/score/src/threadtimeout.c index 300beb5219..f69bc35ea2 100644 --- a/cpukit/score/src/threadtimeout.c +++ b/cpukit/score/src/threadtimeout.c @@ -76,5 +76,11 @@ void _Thread_Timeout( Objects_Id id, void *arg ) if ( unblock ) { _Thread_Unblock( the_thread ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + _Thread_MP_Free_proxy( the_thread ); + } +#endif } } diff --git a/testsuites/sptests/spintrcritical01/init.c b/testsuites/sptests/spintrcritical01/init.c index dc36aee4fd..b7cfee42f8 100644 --- a/testsuites/sptests/spintrcritical01/init.c +++ b/testsuites/sptests/spintrcritical01/init.c @@ -14,12 +14,7 @@ #include #include -#include - -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); -rtems_timer_service_routine test_release_from_isr(rtems_id timer, void *arg); -Thread_blocking_operation_States getState(void); +#include #if defined(FIFO_NO_TIMEOUT) #define TEST_NAME "1" @@ -58,33 +53,28 @@ Thread_blocking_operation_States getState(void); const char rtems_test_name[] = "SPINTRCRITICAL " TEST_NAME; -rtems_id Semaphore; -volatile bool case_hit = false; +static Thread_Control *thread; + +static rtems_id Semaphore; + +static bool case_hit; -Thread_blocking_operation_States getState(void) +static bool interrupts_blocking_op(void) { - Objects_Locations location; - Semaphore_Control *sem; - - sem = (Semaphore_Control *)_Objects_Get( - &_Semaphore_Information, Semaphore, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Thread_Wait_flags flags = _Thread_Wait_flags_get( thread ); - return sem->Core_control.semaphore.Wait_queue.sync_state; + return + flags == ( THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK ); } -rtems_timer_service_routine test_release_from_isr( +static rtems_timer_service_routine test_release_from_isr( rtems_id timer, void *arg ) { rtems_status_code status; - if ( getState() == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { + if ( interrupts_blocking_op() ) { case_hit = true; } @@ -109,7 +99,7 @@ static bool test_body( void *arg ) return case_hit; } -rtems_task Init( +static rtems_task Init( rtems_task_argument ignored ) { @@ -117,6 +107,8 @@ rtems_task Init( TEST_BEGIN(); + thread = _Thread_Get_executing(); + puts( "Init - Trying to generate semaphore release from ISR while blocking" ); puts( "Init - Variation is: " TEST_STRING ); status = rtems_semaphore_create( diff --git a/testsuites/sptests/spintrcritical09/init.c b/testsuites/sptests/spintrcritical09/init.c index 0e38351d43..cc119e88c1 100644 --- a/testsuites/sptests/spintrcritical09/init.c +++ b/testsuites/sptests/spintrcritical09/init.c @@ -14,28 +14,22 @@ #include #include -#include +#include #include const char rtems_test_name[] = "SPINTRCRITICAL 9"; +static Thread_Control *thread; + static rtems_id Semaphore; -static bool case_hit = false; -static Thread_blocking_operation_States getState(void) +static bool case_hit; + +static bool is_interrupt_timeout(void) { - Objects_Locations location; - Semaphore_Control *sem; - - sem = (Semaphore_Control *)_Objects_Get( - &_Semaphore_Information, Semaphore, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Thread_Wait_flags flags = _Thread_Wait_flags_get( thread ); - return sem->Core_control.semaphore.Wait_queue.sync_state; + return flags == ( THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN ); } static rtems_timer_service_routine test_release_from_isr( @@ -50,14 +44,14 @@ static rtems_timer_service_routine test_release_from_isr( if ( watchdog->delta_interval == 0 - && watchdog->routine == _Thread_queue_Timeout + && watchdog->routine == _Thread_Timeout ) { Watchdog_States state = _Watchdog_Remove_ticks( watchdog ); rtems_test_assert( state == WATCHDOG_ACTIVE ); (*watchdog->routine)( watchdog->id, watchdog->user_data ); - if ( getState() == THREAD_BLOCKING_OPERATION_TIMEOUT ) { + if ( is_interrupt_timeout() ) { case_hit = true; } } @@ -81,6 +75,8 @@ static rtems_task Init( TEST_BEGIN(); + thread = _Thread_Get_executing(); + puts( "Init - Test may not be able to detect case is hit reliably" ); puts( "Init - Trying to generate timeout from ISR while blocking" ); sc = rtems_semaphore_create( diff --git a/testsuites/sptests/spintrcritical16/init.c b/testsuites/sptests/spintrcritical16/init.c index 08eeb8b9b4..a094b419b3 100644 --- a/testsuites/sptests/spintrcritical16/init.c +++ b/testsuites/sptests/spintrcritical16/init.c @@ -14,47 +14,36 @@ #include #include -#include +#include const char rtems_test_name[] = "SPINTRCRITICAL 16"; -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); -rtems_timer_service_routine test_release_from_isr(rtems_id timer, void *arg); -Thread_blocking_operation_States getState(void); +static Thread_Control *Main_TCB; -Thread_Control *Main_TCB; -rtems_id Semaphore; -volatile bool case_hit = false; +static rtems_id Semaphore; -Thread_blocking_operation_States getState(void) +static bool case_hit; + +static bool interrupts_blocking_op(void) { - Objects_Locations location; - Semaphore_Control *sem; - - sem = (Semaphore_Control *)_Objects_Get( - &_Semaphore_Information, Semaphore, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Thread_Wait_flags flags = _Thread_Wait_flags_get( Main_TCB ); - return sem->Core_control.semaphore.Wait_queue.sync_state; + return + flags == ( THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK ); } -rtems_timer_service_routine test_release_from_isr( +static rtems_timer_service_routine test_release_from_isr( rtems_id timer, void *arg ) { - if ( getState() == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { + if ( interrupts_blocking_op() ) { case_hit = true; (void) rtems_semaphore_release( Semaphore ); } if ( Main_TCB->Wait.queue != NULL ) { - _Thread_queue_Process_timeout( Main_TCB ); + _Thread_Timeout( 0, Main_TCB ); } } @@ -70,7 +59,7 @@ static bool test_body( void *arg ) return case_hit; } -rtems_task Init( +static rtems_task Init( rtems_task_argument ignored ) { diff --git a/testsuites/sptests/spintrcritical20/init.c b/testsuites/sptests/spintrcritical20/init.c index daa8ac7f7e..7e52211742 100644 --- a/testsuites/sptests/spintrcritical20/init.c +++ b/testsuites/sptests/spintrcritical20/init.c @@ -44,6 +44,10 @@ static void semaphore_task(rtems_task_argument arg) test_context *ctx = (test_context *) arg; ctx->semaphore_task_tcb = _Thread_Get_executing(); + _Thread_Wait_set_timeout_code( + ctx->semaphore_task_tcb, + CORE_SEMAPHORE_TIMEOUT + ); while (true) { rtems_status_code sc = rtems_semaphore_obtain( @@ -87,7 +91,7 @@ static bool test_body(void *arg) ctx->thread_queue_was_null = true; } - _Thread_queue_Process_timeout(ctx->semaphore_task_tcb); + _Thread_Timeout(0, ctx->semaphore_task_tcb); switch (ctx->semaphore_task_tcb->Wait.return_code) { case CORE_SEMAPHORE_STATUS_SUCCESSFUL: @@ -103,7 +107,9 @@ static bool test_body(void *arg) _Thread_Enable_dispatch(); - return false; + return ctx->thread_queue_was_null + && ctx->status_was_successful + && ctx->status_was_timeout; } static void Init(rtems_task_argument ignored) diff --git a/testsuites/sptests/spintrcritical22/init.c b/testsuites/sptests/spintrcritical22/init.c index 93946c39c5..1a377f7838 100644 --- a/testsuites/sptests/spintrcritical22/init.c +++ b/testsuites/sptests/spintrcritical22/init.c @@ -52,14 +52,18 @@ static void release_semaphore(rtems_id timer, void *arg) rtems_status_code sc; CORE_mutex_Control *mtx = &ctx->semaphore_control->Core_control.mutex; - if (mtx->Wait_queue.sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) { + if ( + _Thread_Wait_flags_get(ctx->main_task_control) + == (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK) + ) { ctx->done = true; sc = rtems_semaphore_release(ctx->semaphore_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert( - mtx->Wait_queue.sync_state == THREAD_BLOCKING_OPERATION_SATISFIED + _Thread_Wait_flags_get(ctx->main_task_control) + == (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN) ); rtems_test_assert(mtx->nest_count == 1); rtems_test_assert(mtx->holder == ctx->main_task_control); -- cgit v1.2.3 From f5d6c8b58daf82637bbcf7edb374f65227661a0c Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 27 Apr 2015 16:25:52 +0200 Subject: score: Delete Thread_queue_Control::timeout_status Use a parameter for _Thread_queue_Enqueue() instead to reduce memory usage. --- cpukit/posix/src/condinit.c | 3 +-- cpukit/posix/src/condwaitsupp.c | 3 ++- cpukit/posix/src/psignal.c | 3 +-- cpukit/posix/src/pthread.c | 6 +----- cpukit/posix/src/pthreadjoin.c | 3 ++- cpukit/posix/src/sigtimedwait.c | 1 + cpukit/rtems/src/eventmp.c | 3 ++- cpukit/rtems/src/msgmp.c | 6 ++++-- cpukit/rtems/src/partmp.c | 3 ++- cpukit/rtems/src/regioncreate.c | 3 +-- cpukit/rtems/src/regiongetsegment.c | 3 ++- cpukit/rtems/src/regionmp.c | 3 ++- cpukit/rtems/src/semmp.c | 3 ++- cpukit/rtems/src/signalmp.c | 3 ++- cpukit/rtems/src/taskmp.c | 3 ++- cpukit/score/include/rtems/score/coresemimpl.h | 1 + cpukit/score/include/rtems/score/mpciimpl.h | 4 +++- cpukit/score/include/rtems/score/threadq.h | 5 ----- cpukit/score/include/rtems/score/threadqimpl.h | 12 +++++++----- cpukit/score/src/corebarrier.c | 3 +-- cpukit/score/src/corebarrierwait.c | 1 + cpukit/score/src/coremsg.c | 3 +-- cpukit/score/src/coremsgseize.c | 1 + cpukit/score/src/coremsgsubmit.c | 3 ++- cpukit/score/src/coremutex.c | 3 +-- cpukit/score/src/coremutexseize.c | 1 + cpukit/score/src/corerwlock.c | 3 +-- cpukit/score/src/corerwlockobtainread.c | 1 + cpukit/score/src/corerwlockobtainwrite.c | 1 + cpukit/score/src/coresem.c | 3 +-- cpukit/score/src/coresemseize.c | 1 + cpukit/score/src/mpci.c | 9 +++++---- cpukit/score/src/threadq.c | 7 ++----- cpukit/score/src/threadqenqueue.c | 6 ++---- 34 files changed, 60 insertions(+), 57 deletions(-) diff --git a/cpukit/posix/src/condinit.c b/cpukit/posix/src/condinit.c index c1c14b8bf9..0b61d14cb9 100644 --- a/cpukit/posix/src/condinit.c +++ b/cpukit/posix/src/condinit.c @@ -64,8 +64,7 @@ int pthread_cond_init( _Thread_queue_Initialize( &the_cond->Wait_queue, - THREAD_QUEUE_DISCIPLINE_FIFO, - ETIMEDOUT + THREAD_QUEUE_DISCIPLINE_FIFO ); _Objects_Open_u32( diff --git a/cpukit/posix/src/condwaitsupp.c b/cpukit/posix/src/condwaitsupp.c index 8a9e23540c..5a71dc3b54 100644 --- a/cpukit/posix/src/condwaitsupp.c +++ b/cpukit/posix/src/condwaitsupp.c @@ -83,7 +83,8 @@ int _POSIX_Condition_variables_Wait_support( executing, STATES_WAITING_FOR_CONDITION_VARIABLE | STATES_INTERRUPTIBLE_BY_SIGNAL, - timeout + timeout, + ETIMEDOUT ); _Objects_Put( &the_cond->Object ); diff --git a/cpukit/posix/src/psignal.c b/cpukit/posix/src/psignal.c index 543b558eac..3ca0723860 100644 --- a/cpukit/posix/src/psignal.c +++ b/cpukit/posix/src/psignal.c @@ -190,8 +190,7 @@ void _POSIX_signals_Manager_Initialization(void) */ _Thread_queue_Initialize( &_POSIX_signals_Wait_queue, - THREAD_QUEUE_DISCIPLINE_FIFO, - EAGAIN + THREAD_QUEUE_DISCIPLINE_FIFO ); /* XXX status codes */ diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index 2817891ac5..a3a73f117a 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -235,11 +235,7 @@ static bool _POSIX_Threads_Create_extension( _POSIX_signals_Action_handler ); - _Thread_queue_Initialize( - &api->Join_List, - THREAD_QUEUE_DISCIPLINE_FIFO, - 0 - ); + _Thread_queue_Initialize( &api->Join_List, THREAD_QUEUE_DISCIPLINE_FIFO ); _Watchdog_Initialize( &api->Sporadic_timer, diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c index 48fb7d58df..f7361310c4 100644 --- a/cpukit/posix/src/pthreadjoin.c +++ b/cpukit/posix/src/pthreadjoin.c @@ -71,7 +71,8 @@ on_EINTR: &api->Join_List, executing, STATES_WAITING_FOR_JOIN | STATES_INTERRUPTIBLE_BY_SIGNAL, - WATCHDOG_NO_TIMEOUT + WATCHDOG_NO_TIMEOUT, + 0 ); } _Objects_Put( &the_thread->Object ); diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c index e988761453..fb8a243a0a 100644 --- a/cpukit/posix/src/sigtimedwait.c +++ b/cpukit/posix/src/sigtimedwait.c @@ -160,6 +160,7 @@ int sigtimedwait( executing, STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL, interval, + EAGAIN, &lock_context ); _Thread_Enable_dispatch(); diff --git a/cpukit/rtems/src/eventmp.c b/cpukit/rtems/src/eventmp.c index b2a5ce8a72..e2e43fcd0d 100644 --- a/cpukit/rtems/src/eventmp.c +++ b/cpukit/rtems/src/eventmp.c @@ -59,7 +59,8 @@ rtems_status_code _Event_MP_Send_request_packet ( _MPCI_Send_request_packet( _Objects_Get_node( event_id ), &the_packet->Prefix, - STATES_READY + STATES_READY, + RTEMS_TIMEOUT ); break; diff --git a/cpukit/rtems/src/msgmp.c b/cpukit/rtems/src/msgmp.c index ddad64a17a..83b5a31f52 100644 --- a/cpukit/rtems/src/msgmp.c +++ b/cpukit/rtems/src/msgmp.c @@ -148,7 +148,8 @@ rtems_status_code _Message_queue_MP_Send_request_packet ( return (rtems_status_code) _MPCI_Send_request_packet( _Objects_Get_node(message_queue_id), &the_packet->Prefix, - STATES_WAITING_FOR_MESSAGE + STATES_WAITING_FOR_MESSAGE, + RTEMS_TIMEOUT ); break; @@ -173,7 +174,8 @@ rtems_status_code _Message_queue_MP_Send_request_packet ( return (rtems_status_code) _MPCI_Send_request_packet( _Objects_Get_node(message_queue_id), &the_packet->Prefix, - STATES_WAITING_FOR_MESSAGE + STATES_WAITING_FOR_MESSAGE, + RTEMS_TIMEOUT ); break; diff --git a/cpukit/rtems/src/partmp.c b/cpukit/rtems/src/partmp.c index f41fd227e9..9593ce58a9 100644 --- a/cpukit/rtems/src/partmp.c +++ b/cpukit/rtems/src/partmp.c @@ -104,7 +104,8 @@ rtems_status_code _Partition_MP_Send_request_packet ( _MPCI_Send_request_packet( _Objects_Get_node( partition_id ), &the_packet->Prefix, - STATES_READY /* Not used */ + STATES_READY, /* Not used */ + RTEMS_TIMEOUT ); break; diff --git a/cpukit/rtems/src/regioncreate.c b/cpukit/rtems/src/regioncreate.c index aa95f3231b..409510c892 100644 --- a/cpukit/rtems/src/regioncreate.c +++ b/cpukit/rtems/src/regioncreate.c @@ -74,8 +74,7 @@ rtems_status_code rtems_region_create( _Thread_queue_Initialize( &the_region->Wait_queue, _Attributes_Is_priority( attribute_set ) ? - THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, - RTEMS_TIMEOUT + THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO ); the_region->maximum_segment_size = _Heap_Initialize( diff --git a/cpukit/rtems/src/regiongetsegment.c b/cpukit/rtems/src/regiongetsegment.c index cef90e79f3..1e5c795697 100644 --- a/cpukit/rtems/src/regiongetsegment.c +++ b/cpukit/rtems/src/regiongetsegment.c @@ -87,7 +87,8 @@ rtems_status_code rtems_region_get_segment( &the_region->Wait_queue, executing, STATES_WAITING_FOR_SEGMENT, - timeout + timeout, + RTEMS_TIMEOUT ); _Objects_Put( &the_region->Object ); diff --git a/cpukit/rtems/src/regionmp.c b/cpukit/rtems/src/regionmp.c index 8bce822193..135a69dd97 100644 --- a/cpukit/rtems/src/regionmp.c +++ b/cpukit/rtems/src/regionmp.c @@ -102,7 +102,8 @@ rtems_status_code _Region_MP_Send_request_packet ( return (rtems_status_code) _MPCI_Send_request_packet( _Objects_Get_node( region_id ), &the_packet->Prefix, - STATES_READY /* Not used */ + STATES_READY, /* Not used */ + RTEMS_TIMEOUT ); break; diff --git a/cpukit/rtems/src/semmp.c b/cpukit/rtems/src/semmp.c index d94d90870a..f4c5cb73df 100644 --- a/cpukit/rtems/src/semmp.c +++ b/cpukit/rtems/src/semmp.c @@ -95,7 +95,8 @@ rtems_status_code _Semaphore_MP_Send_request_packet ( return _MPCI_Send_request_packet( _Objects_Get_node( semaphore_id ), &the_packet->Prefix, - STATES_WAITING_FOR_SEMAPHORE + STATES_WAITING_FOR_SEMAPHORE, + RTEMS_TIMEOUT ); break; diff --git a/cpukit/rtems/src/signalmp.c b/cpukit/rtems/src/signalmp.c index 9d2177d214..4a2d5738af 100644 --- a/cpukit/rtems/src/signalmp.c +++ b/cpukit/rtems/src/signalmp.c @@ -60,7 +60,8 @@ rtems_status_code _Signal_MP_Send_request_packet ( return _MPCI_Send_request_packet( _Objects_Get_node( task_id ), &the_packet->Prefix, - STATES_READY /* Not used */ + STATES_READY, /* Not used */ + RTEMS_TIMEOUT ); break; diff --git a/cpukit/rtems/src/taskmp.c b/cpukit/rtems/src/taskmp.c index 4b97ffe639..339544cdc4 100644 --- a/cpukit/rtems/src/taskmp.c +++ b/cpukit/rtems/src/taskmp.c @@ -108,7 +108,8 @@ rtems_status_code _RTEMS_tasks_MP_Send_request_packet ( return _MPCI_Send_request_packet( _Objects_Get_node( task_id ), &the_packet->Prefix, - STATES_READY /* Not used */ + STATES_READY, /* Not used */ + RTEMS_TIMEOUT ); break; diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index fac9f689e4..3e1d481ab8 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -248,6 +248,7 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Seize_isr_disable( executing, STATES_WAITING_FOR_SEMAPHORE, timeout, + CORE_SEMAPHORE_TIMEOUT, lock_context ); _Thread_Enable_dispatch(); diff --git a/cpukit/score/include/rtems/score/mpciimpl.h b/cpukit/score/include/rtems/score/mpciimpl.h index 22dff883a2..5652f6afa1 100644 --- a/cpukit/score/include/rtems/score/mpciimpl.h +++ b/cpukit/score/include/rtems/score/mpciimpl.h @@ -189,13 +189,15 @@ void _MPCI_Send_process_packet ( * set in addition to the remote operation pending state. It * may indicate the caller is blocking on a message queue * operation. + * @param[in] timeout_code is the timeout code * * @retval This method returns the operation status from the remote node. */ uint32_t _MPCI_Send_request_packet ( uint32_t destination, MP_packet_Prefix *the_packet, - States_Control extra_state + States_Control extra_state, + uint32_t timeout_code ); /** diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index b89198608a..4a8db7c59d 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -194,11 +194,6 @@ struct Thread_queue_Control { * _Thread_queue_Release(). */ ISR_LOCK_MEMBER( Lock ) - - /** This is the status value returned to threads which timeout while - * waiting on this thread queue. - */ - uint32_t timeout_status; }; /**@}*/ diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 9893aae8af..79fc810b9b 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -134,6 +134,7 @@ Thread_Control *_Thread_queue_Dequeue( * @param[in] state The new state of the thread. * @param[in] timeout Interval to wait. Use WATCHDOG_NO_TIMEOUT to block * potentially forever. + * @param[in] timeout_code The return code in case a timeout occurs. * @param[in] lock_context The lock context of the lock acquire. */ void _Thread_queue_Enqueue_critical( @@ -141,6 +142,7 @@ void _Thread_queue_Enqueue_critical( Thread_Control *the_thread, States_Control state, Watchdog_Interval timeout, + uint32_t timeout_code, ISR_lock_Context *lock_context ); @@ -152,7 +154,8 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, States_Control state, - Watchdog_Interval timeout + Watchdog_Interval timeout, + uint32_t timeout_code ) { ISR_lock_Context lock_context; @@ -163,6 +166,7 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( the_thread, state, timeout, + timeout_code, &lock_context ); } @@ -332,12 +336,10 @@ void _Thread_queue_Flush( * * @param[in] the_thread_queue is the pointer to a threadq header * @param[in] the_discipline is the queueing discipline - * @param[in] timeout_status is the return on a timeout */ void _Thread_queue_Initialize( - Thread_queue_Control *the_thread_queue, - Thread_queue_Disciplines the_discipline, - uint32_t timeout_status + Thread_queue_Control *the_thread_queue, + Thread_queue_Disciplines the_discipline ); RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy( diff --git a/cpukit/score/src/corebarrier.c b/cpukit/score/src/corebarrier.c index 2035961b92..eddf901934 100644 --- a/cpukit/score/src/corebarrier.c +++ b/cpukit/score/src/corebarrier.c @@ -32,7 +32,6 @@ void _CORE_barrier_Initialize( _Thread_queue_Initialize( &the_barrier->Wait_queue, - THREAD_QUEUE_DISCIPLINE_FIFO, - CORE_BARRIER_TIMEOUT + THREAD_QUEUE_DISCIPLINE_FIFO ); } diff --git a/cpukit/score/src/corebarrierwait.c b/cpukit/score/src/corebarrierwait.c index 30abf0c17a..39687d31da 100644 --- a/cpukit/score/src/corebarrierwait.c +++ b/cpukit/score/src/corebarrierwait.c @@ -54,6 +54,7 @@ void _CORE_barrier_Wait( executing, STATES_WAITING_FOR_BARRIER, timeout, + CORE_BARRIER_TIMEOUT, &lock_context ); } diff --git a/cpukit/score/src/coremsg.c b/cpukit/score/src/coremsg.c index 0790221eb9..ae2bc753c7 100644 --- a/cpukit/score/src/coremsg.c +++ b/cpukit/score/src/coremsg.c @@ -111,8 +111,7 @@ bool _CORE_message_queue_Initialize( _Thread_queue_Initialize( &the_message_queue->Wait_queue, _CORE_message_queue_Is_priority( the_message_queue_attributes ) ? - THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, - CORE_MESSAGE_QUEUE_STATUS_TIMEOUT + THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO ); return true; diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c index 45105ca19b..ec6cf8c52e 100644 --- a/cpukit/score/src/coremsgseize.c +++ b/cpukit/score/src/coremsgseize.c @@ -124,6 +124,7 @@ void _CORE_message_queue_Seize( executing, STATES_WAITING_FOR_MESSAGE, timeout, + CORE_MESSAGE_QUEUE_STATUS_TIMEOUT, &lock_context ); } diff --git a/cpukit/score/src/coremsgsubmit.c b/cpukit/score/src/coremsgsubmit.c index 0bcebe04af..0d0965ffbf 100644 --- a/cpukit/score/src/coremsgsubmit.c +++ b/cpukit/score/src/coremsgsubmit.c @@ -129,7 +129,8 @@ CORE_message_queue_Status _CORE_message_queue_Submit( &the_message_queue->Wait_queue, executing, STATES_WAITING_FOR_MESSAGE, - timeout + timeout, + CORE_MESSAGE_QUEUE_STATUS_TIMEOUT ); } diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c index b5e8a5ed4b..2f584f2abf 100644 --- a/cpukit/score/src/coremutex.c +++ b/cpukit/score/src/coremutex.c @@ -83,8 +83,7 @@ CORE_mutex_Status _CORE_mutex_Initialize( _Thread_queue_Initialize( &the_mutex->Wait_queue, _CORE_mutex_Is_fifo( the_mutex_attributes ) ? - THREAD_QUEUE_DISCIPLINE_FIFO : THREAD_QUEUE_DISCIPLINE_PRIORITY, - CORE_MUTEX_TIMEOUT + THREAD_QUEUE_DISCIPLINE_FIFO : THREAD_QUEUE_DISCIPLINE_PRIORITY ); return CORE_MUTEX_STATUS_SUCCESSFUL; diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 67954b697b..4ecb702305 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -81,6 +81,7 @@ void _CORE_mutex_Seize_interrupt_blocking( executing, STATES_WAITING_FOR_MUTEX, timeout, + CORE_MUTEX_TIMEOUT, lock_context ); diff --git a/cpukit/score/src/corerwlock.c b/cpukit/score/src/corerwlock.c index 0d47db4b23..8b74c4119c 100644 --- a/cpukit/score/src/corerwlock.c +++ b/cpukit/score/src/corerwlock.c @@ -36,7 +36,6 @@ void _CORE_RWLock_Initialize( _Thread_queue_Initialize( &the_rwlock->Wait_queue, - THREAD_QUEUE_DISCIPLINE_FIFO, - CORE_RWLOCK_TIMEOUT + THREAD_QUEUE_DISCIPLINE_FIFO ); } diff --git a/cpukit/score/src/corerwlockobtainread.c b/cpukit/score/src/corerwlockobtainread.c index 59c1097354..0dea50f1e8 100644 --- a/cpukit/score/src/corerwlockobtainread.c +++ b/cpukit/score/src/corerwlockobtainread.c @@ -87,6 +87,7 @@ void _CORE_RWLock_Obtain_for_reading( executing, STATES_WAITING_FOR_RWLOCK, timeout, + CORE_RWLOCK_TIMEOUT, &lock_context ); diff --git a/cpukit/score/src/corerwlockobtainwrite.c b/cpukit/score/src/corerwlockobtainwrite.c index 409d31aeec..76dfae2776 100644 --- a/cpukit/score/src/corerwlockobtainwrite.c +++ b/cpukit/score/src/corerwlockobtainwrite.c @@ -77,6 +77,7 @@ void _CORE_RWLock_Obtain_for_writing( executing, STATES_WAITING_FOR_RWLOCK, timeout, + CORE_RWLOCK_TIMEOUT, &lock_context ); diff --git a/cpukit/score/src/coresem.c b/cpukit/score/src/coresem.c index eb1ba7e283..2475c349a7 100644 --- a/cpukit/score/src/coresem.c +++ b/cpukit/score/src/coresem.c @@ -33,7 +33,6 @@ void _CORE_semaphore_Initialize( _Thread_queue_Initialize( &the_semaphore->Wait_queue, _CORE_semaphore_Is_priority( the_semaphore_attributes ) ? - THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, - CORE_SEMAPHORE_TIMEOUT + THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO ); } diff --git a/cpukit/score/src/coresemseize.c b/cpukit/score/src/coresemseize.c index d7ab28e779..6ecf2c4c8f 100644 --- a/cpukit/score/src/coresemseize.c +++ b/cpukit/score/src/coresemseize.c @@ -65,6 +65,7 @@ void _CORE_semaphore_Seize( executing, STATES_WAITING_FOR_SEMAPHORE, timeout, + CORE_SEMAPHORE_TIMEOUT, &lock_context ); } diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 9915aa2d12..7fd77f7597 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -82,8 +82,7 @@ void _MPCI_Handler_initialization( _Thread_queue_Initialize( &_MPCI_Remote_blocked_threads, - THREAD_QUEUE_DISCIPLINE_FIFO, - timeout_status + THREAD_QUEUE_DISCIPLINE_FIFO ); } @@ -188,7 +187,8 @@ void _MPCI_Send_process_packet ( uint32_t _MPCI_Send_request_packet ( uint32_t destination, MP_packet_Prefix *the_packet, - States_Control extra_state + States_Control extra_state, + uint32_t timeout_code ) { Thread_Control *executing = _Thread_Executing; @@ -217,7 +217,8 @@ uint32_t _MPCI_Send_request_packet ( &_MPCI_Remote_blocked_threads, executing, STATES_WAITING_FOR_RPC_REPLY | extra_state, - the_packet->timeout + the_packet->timeout, + timeout_code ); _Thread_Enable_dispatch(); diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c index cdb99498fe..3b1b47bf3a 100644 --- a/cpukit/score/src/threadq.c +++ b/cpukit/score/src/threadq.c @@ -44,15 +44,12 @@ RBTree_Compare_result _Thread_queue_Compare_priority( } void _Thread_queue_Initialize( - Thread_queue_Control *the_thread_queue, - Thread_queue_Disciplines the_discipline, - uint32_t timeout_status + Thread_queue_Control *the_thread_queue, + Thread_queue_Disciplines the_discipline ) { const Thread_queue_Operations *operations; - the_thread_queue->timeout_status = timeout_status; - _ISR_lock_Initialize( &the_thread_queue->Lock, "Thread Queue" ); if ( the_discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index d02f2ee073..714552509e 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -50,6 +50,7 @@ void _Thread_queue_Enqueue_critical( Thread_Control *the_thread, States_Control state, Watchdog_Interval timeout, + uint32_t timeout_code, ISR_lock_Context *lock_context ) { @@ -83,10 +84,7 @@ void _Thread_queue_Enqueue_critical( * If the thread wants to timeout, then schedule its timer. */ if ( timeout != WATCHDOG_NO_TIMEOUT ) { - _Thread_Wait_set_timeout_code( - the_thread, - the_thread_queue->timeout_status - ); + _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 ); } -- cgit v1.2.3 From c654b52517c2d255aa98eed347edeba60dc854d0 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 30 Apr 2015 13:18:45 +0200 Subject: score: Delete _CORE_message_queue_Flush_support() Check the number of pending messages in _CORE_message_queue_Flush() to avoid race conditions. --- cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/coremsgimpl.h | 17 ------ cpukit/score/src/coremsgclose.c | 3 +- cpukit/score/src/coremsgflush.c | 72 ++++++++++++++++++---- cpukit/score/src/coremsgflushsupp.c | 84 -------------------------- 5 files changed, 62 insertions(+), 116 deletions(-) delete mode 100644 cpukit/score/src/coremsgflushsupp.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 19d3237607..6d4414c430 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -158,7 +158,7 @@ libscore_a_SOURCES += src/corebarrier.c src/corebarrierrelease.c \ ## CORE_MESSAGE_QUEUE_C_FILES libscore_a_SOURCES += src/coremsg.c src/coremsgbroadcast.c \ src/coremsgclose.c src/coremsgflush.c src/coremsgflushwait.c \ - src/coremsginsert.c src/coremsgflushsupp.c src/coremsgseize.c \ + src/coremsginsert.c src/coremsgseize.c \ src/coremsgsubmit.c ## CORE_MUTEX_C_FILES diff --git a/cpukit/score/include/rtems/score/coremsgimpl.h b/cpukit/score/include/rtems/score/coremsgimpl.h index cedf2760e8..1f6796905b 100644 --- a/cpukit/score/include/rtems/score/coremsgimpl.h +++ b/cpukit/score/include/rtems/score/coremsgimpl.h @@ -179,23 +179,6 @@ uint32_t _CORE_message_queue_Flush( CORE_message_queue_Control *the_message_queue ); -/** - * @brief Flush all outstanding messages. - * - * This routine flushes all outstanding messages and returns - * them to the inactive message chain. - * - * @param[in] the_message_queue points to the message queue to flush - * - * @retval This method returns the number of pending messages flushed. - * - * - INTERRUPT LATENCY: - * + single case - */ -uint32_t _CORE_message_queue_Flush_support( - CORE_message_queue_Control *the_message_queue -); - #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) /** * @brief Flush waiting threads. diff --git a/cpukit/score/src/coremsgclose.c b/cpukit/score/src/coremsgclose.c index 17ecc4428e..d808a4efbc 100644 --- a/cpukit/score/src/coremsgclose.c +++ b/cpukit/score/src/coremsgclose.c @@ -49,8 +49,7 @@ void _CORE_message_queue_Close( * the flush satisfying any blocked senders as a side-effect. */ - if ( the_message_queue->number_of_pending_messages != 0 ) - (void) _CORE_message_queue_Flush_support( the_message_queue ); + (void) _CORE_message_queue_Flush( the_message_queue ); (void) _Workspace_Free( the_message_queue->message_buffers ); diff --git a/cpukit/score/src/coremsgflush.c b/cpukit/score/src/coremsgflush.c index 51f6c8db98..05683f0327 100644 --- a/cpukit/score/src/coremsgflush.c +++ b/cpukit/score/src/coremsgflush.c @@ -1,8 +1,9 @@ /** - * @file + * @file * - * @brief Flush Pending Messages - * @ingroup ScoreMessageQueue + * @brief Flush Messages Routine + * + * @ingroup ScoreMessageQueue */ /* @@ -18,19 +19,66 @@ #include "config.h" #endif -#include -#include -#include #include -#include -#include +#include uint32_t _CORE_message_queue_Flush( CORE_message_queue_Control *the_message_queue ) { - if ( the_message_queue->number_of_pending_messages != 0 ) - return _CORE_message_queue_Flush_support( the_message_queue ); - else - return 0; + ISR_Level level; + Chain_Node *inactive_head; + Chain_Node *inactive_first; + Chain_Node *message_queue_first; + Chain_Node *message_queue_last; + uint32_t count; + + /* + * Currently, RTEMS supports no API that has both flush and blocking + * sends. Thus, this routine assumes that there are no senders + * blocked waiting to send messages. In the event, that an API is + * added that can flush a message queue when threads are blocked + * waiting to send, there are two basic behaviors envisioned: + * + * (1) The thread queue of pending senders is a logical extension + * of the pending message queue. In this case, it should be + * flushed using the _Thread_queue_Flush() service with a status + * such as CORE_MESSAGE_QUEUE_SENDER_FLUSHED (which currently does + * not exist). This can be implemented without changing the "big-O" + * of the message flushing part of the routine. + * + * (2) Only the actual messages queued should be purged. In this case, + * the blocked sender threads must be allowed to send their messages. + * In this case, the implementation will be forced to individually + * dequeue the senders and queue their messages. This will force + * this routine to have "big O(n)" where n is the number of blocked + * senders. If there are more messages pending than senders blocked, + * then the existing flush code can be used to dispose of the remaining + * pending messages. + * + * For now, though, we are very happy to have a small routine with + * fixed execution time that only deals with pending messages. + */ + + _ISR_Disable( level ); + + count = the_message_queue->number_of_pending_messages; + if ( count != 0 ) { + the_message_queue->number_of_pending_messages = 0; + + inactive_head = _Chain_Head( &the_message_queue->Inactive_messages ); + inactive_first = inactive_head->next; + message_queue_first = _Chain_First( &the_message_queue->Pending_messages ); + message_queue_last = _Chain_Last( &the_message_queue->Pending_messages ); + + inactive_head->next = message_queue_first; + message_queue_last->next = inactive_first; + inactive_first->previous = message_queue_last; + message_queue_first->previous = inactive_head; + + _Chain_Initialize_empty( &the_message_queue->Pending_messages ); + } + + _ISR_Enable( level ); + return count; } diff --git a/cpukit/score/src/coremsgflushsupp.c b/cpukit/score/src/coremsgflushsupp.c deleted file mode 100644 index 041972fb9c..0000000000 --- a/cpukit/score/src/coremsgflushsupp.c +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file - * - * @brief Flush Messages Support Routine - * - * @ingroup ScoreMessageQueue - */ - -/* - * 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 -#include -#include -#include -#include -#include - -uint32_t _CORE_message_queue_Flush_support( - CORE_message_queue_Control *the_message_queue -) -{ - ISR_Level level; - Chain_Node *inactive_head; - Chain_Node *inactive_first; - Chain_Node *message_queue_first; - Chain_Node *message_queue_last; - uint32_t count; - - /* - * Currently, RTEMS supports no API that has both flush and blocking - * sends. Thus, this routine assumes that there are no senders - * blocked waiting to send messages. In the event, that an API is - * added that can flush a message queue when threads are blocked - * waiting to send, there are two basic behaviors envisioned: - * - * (1) The thread queue of pending senders is a logical extension - * of the pending message queue. In this case, it should be - * flushed using the _Thread_queue_Flush() service with a status - * such as CORE_MESSAGE_QUEUE_SENDER_FLUSHED (which currently does - * not exist). This can be implemented without changing the "big-O" - * of the message flushing part of the routine. - * - * (2) Only the actual messages queued should be purged. In this case, - * the blocked sender threads must be allowed to send their messages. - * In this case, the implementation will be forced to individually - * dequeue the senders and queue their messages. This will force - * this routine to have "big O(n)" where n is the number of blocked - * senders. If there are more messages pending than senders blocked, - * then the existing flush code can be used to dispose of the remaining - * pending messages. - * - * For now, though, we are very happy to have a small routine with - * fixed execution time that only deals with pending messages. - */ - - _ISR_Disable( level ); - inactive_head = _Chain_Head( &the_message_queue->Inactive_messages ); - inactive_first = inactive_head->next; - message_queue_first = _Chain_First( &the_message_queue->Pending_messages ); - message_queue_last = _Chain_Last( &the_message_queue->Pending_messages ); - - inactive_head->next = message_queue_first; - message_queue_last->next = inactive_first; - inactive_first->previous = message_queue_last; - message_queue_first->previous = inactive_head; - - _Chain_Initialize_empty( &the_message_queue->Pending_messages ); - - count = the_message_queue->number_of_pending_messages; - the_message_queue->number_of_pending_messages = 0; - _ISR_Enable( level ); - return count; -} -- cgit v1.2.3 From cc18d7bec7b3c5515cb9e6cd9771d4b94309b3bd Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 30 Apr 2015 13:12:54 +0200 Subject: score: Fine grained locking for message queues Aggregate several critical sections into a bigger one. Sending and receiving messages is now protected by an ISR lock. Thread dispatching is only disabled in case a blocking operation is necessary. The message copy procedure is done inside the critical section (interrupts disabled). Thus this change may have a negative impact on the interrupt latency in case very large messages are transferred. Update #2273. --- cpukit/posix/include/rtems/posix/mqueueimpl.h | 15 +++ cpukit/posix/src/mqueuerecvsupp.c | 15 ++- cpukit/posix/src/mqueuesendsupp.c | 14 ++- cpukit/rtems/include/rtems/rtems/messageimpl.h | 15 +++ cpukit/rtems/src/msgqbroadcast.c | 12 ++- cpukit/rtems/src/msgqflush.c | 13 ++- cpukit/rtems/src/msgqreceive.c | 11 ++- cpukit/rtems/src/msgqsend.c | 12 ++- cpukit/rtems/src/msgqurgent.c | 11 ++- cpukit/score/include/rtems/score/coremsgimpl.h | 121 ++++++++++++++++++++++--- cpukit/score/src/coremsgbroadcast.c | 61 +++++-------- cpukit/score/src/coremsgclose.c | 8 +- cpukit/score/src/coremsgflush.c | 9 +- cpukit/score/src/coremsginsert.c | 6 -- cpukit/score/src/coremsgseize.c | 30 ++++-- cpukit/score/src/coremsgsubmit.c | 81 +++++++++-------- doc/user/msg.t | 5 +- 17 files changed, 303 insertions(+), 136 deletions(-) diff --git a/cpukit/posix/include/rtems/posix/mqueueimpl.h b/cpukit/posix/include/rtems/posix/mqueueimpl.h index bfc850d990..90269bf57b 100644 --- a/cpukit/posix/include/rtems/posix/mqueueimpl.h +++ b/cpukit/posix/include/rtems/posix/mqueueimpl.h @@ -250,6 +250,21 @@ RTEMS_INLINE_ROUTINE POSIX_Message_queue_Control_fd *_POSIX_Message_queue_Get_fd location ); } + +RTEMS_INLINE_ROUTINE POSIX_Message_queue_Control_fd * +_POSIX_Message_queue_Get_fd_interrupt_disable( + mqd_t id, + Objects_Locations *location, + ISR_lock_Context *lock_context +) +{ + return (POSIX_Message_queue_Control_fd *) _Objects_Get_isr_disable( + &_POSIX_Message_queue_Information_fds, + (Objects_Id)id, + location, + lock_context + ); +} /** * @see _POSIX_Name_to_id(). diff --git a/cpukit/posix/src/mqueuerecvsupp.c b/cpukit/posix/src/mqueuerecvsupp.c index bea19fe9ca..2f9bb2d276 100644 --- a/cpukit/posix/src/mqueuerecvsupp.c +++ b/cpukit/posix/src/mqueuerecvsupp.c @@ -54,20 +54,25 @@ ssize_t _POSIX_Message_queue_Receive_support( size_t length_out; bool do_wait; Thread_Control *executing; + ISR_lock_Context lock_context; - the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + the_mq_fd = _POSIX_Message_queue_Get_fd_interrupt_disable( + mqdes, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: if ( (the_mq_fd->oflag & O_ACCMODE) == O_WRONLY ) { - _Objects_Put( &the_mq_fd->Object ); + _ISR_lock_ISR_enable( &lock_context ); rtems_set_errno_and_return_minus_one( EBADF ); } the_mq = the_mq_fd->Queue; if ( msg_len < the_mq->Message_queue.maximum_message_size ) { - _Objects_Put( &the_mq_fd->Object ); + _ISR_lock_ISR_enable( &lock_context ); rtems_set_errno_and_return_minus_one( EMSGSIZE ); } @@ -97,10 +102,10 @@ ssize_t _POSIX_Message_queue_Receive_support( msg_ptr, &length_out, do_wait, - timeout + timeout, + &lock_context ); - _Objects_Put( &the_mq_fd->Object ); if (msg_prio) { *msg_prio = _POSIX_Message_queue_Priority_from_core( executing->Wait.count diff --git a/cpukit/posix/src/mqueuesendsupp.c b/cpukit/posix/src/mqueuesendsupp.c index 2d6ddae859..d73538ae88 100644 --- a/cpukit/posix/src/mqueuesendsupp.c +++ b/cpukit/posix/src/mqueuesendsupp.c @@ -64,6 +64,7 @@ int _POSIX_Message_queue_Send_support( CORE_message_queue_Status msg_status; bool do_wait; Thread_Control *executing; + ISR_lock_Context lock_context; /* * Validate the priority. @@ -73,12 +74,16 @@ int _POSIX_Message_queue_Send_support( if ( msg_prio > MQ_PRIO_MAX ) rtems_set_errno_and_return_minus_one( EINVAL ); - the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + the_mq_fd = _POSIX_Message_queue_Get_fd_interrupt_disable( + mqdes, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: if ( (the_mq_fd->oflag & O_ACCMODE) == O_RDONLY ) { - _Objects_Put( &the_mq_fd->Object ); + _ISR_lock_ISR_enable( &lock_context ); rtems_set_errno_and_return_minus_one( EBADF ); } @@ -105,11 +110,10 @@ int _POSIX_Message_queue_Send_support( NULL, _POSIX_Message_queue_Priority_to_core( msg_prio ), do_wait, - timeout /* no timeout */ + timeout, /* no timeout */ + &lock_context ); - _Objects_Put( &the_mq_fd->Object ); - /* * If we had to block, then this is where the task returns * after it wakes up. The returned status is correct for diff --git a/cpukit/rtems/include/rtems/rtems/messageimpl.h b/cpukit/rtems/include/rtems/rtems/messageimpl.h index fa9e573892..2399d65f29 100644 --- a/cpukit/rtems/include/rtems/rtems/messageimpl.h +++ b/cpukit/rtems/include/rtems/rtems/messageimpl.h @@ -139,6 +139,21 @@ RTEMS_INLINE_ROUTINE Message_queue_Control *_Message_queue_Get ( _Objects_Get( &_Message_queue_Information, id, location ); } +RTEMS_INLINE_ROUTINE Message_queue_Control * +_Message_queue_Get_interrupt_disable( + Objects_Id id, + Objects_Locations *location, + ISR_lock_Context *lock_context +) +{ + return (Message_queue_Control *) _Objects_Get_isr_disable( + &_Message_queue_Information, + id, + location, + lock_context + ); +} + RTEMS_INLINE_ROUTINE Message_queue_Control *_Message_queue_Allocate( void ) { return (Message_queue_Control *) diff --git a/cpukit/rtems/src/msgqbroadcast.c b/cpukit/rtems/src/msgqbroadcast.c index 64ea80e3de..aabbf3f6ac 100644 --- a/cpukit/rtems/src/msgqbroadcast.c +++ b/cpukit/rtems/src/msgqbroadcast.c @@ -40,6 +40,7 @@ rtems_status_code rtems_message_queue_broadcast( Message_queue_Control *the_message_queue; Objects_Locations location; CORE_message_queue_Status core_status; + ISR_lock_Context lock_context; if ( !buffer ) return RTEMS_INVALID_ADDRESS; @@ -47,7 +48,11 @@ rtems_status_code rtems_message_queue_broadcast( if ( !count ) return RTEMS_INVALID_ADDRESS; - the_message_queue = _Message_queue_Get( id, &location ); + the_message_queue = _Message_queue_Get_interrupt_disable( + id, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -61,10 +66,9 @@ rtems_status_code rtems_message_queue_broadcast( #else NULL, #endif - count + count, + &lock_context ); - - _Objects_Put( &the_message_queue->Object ); return _Message_queue_Translate_core_message_queue_return_code( core_status ); diff --git a/cpukit/rtems/src/msgqflush.c b/cpukit/rtems/src/msgqflush.c index 7ae7ef4544..809c243b52 100644 --- a/cpukit/rtems/src/msgqflush.c +++ b/cpukit/rtems/src/msgqflush.c @@ -54,16 +54,23 @@ rtems_status_code rtems_message_queue_flush( { Message_queue_Control *the_message_queue; Objects_Locations location; + ISR_lock_Context lock_context; if ( !count ) return RTEMS_INVALID_ADDRESS; - the_message_queue = _Message_queue_Get( id, &location ); + the_message_queue = _Message_queue_Get_interrupt_disable( + id, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: - *count = _CORE_message_queue_Flush( &the_message_queue->message_queue ); - _Objects_Put( &the_message_queue->Object ); + *count = _CORE_message_queue_Flush( + &the_message_queue->message_queue, + &lock_context + ); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/msgqreceive.c b/cpukit/rtems/src/msgqreceive.c index db09cfe547..2b9a4e742b 100644 --- a/cpukit/rtems/src/msgqreceive.c +++ b/cpukit/rtems/src/msgqreceive.c @@ -42,6 +42,7 @@ rtems_status_code rtems_message_queue_receive( Objects_Locations location; bool wait; Thread_Control *executing; + ISR_lock_Context lock_context; if ( !buffer ) return RTEMS_INVALID_ADDRESS; @@ -49,7 +50,11 @@ rtems_status_code rtems_message_queue_receive( if ( !size ) return RTEMS_INVALID_ADDRESS; - the_message_queue = _Message_queue_Get( id, &location ); + the_message_queue = _Message_queue_Get_interrupt_disable( + id, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -66,9 +71,9 @@ rtems_status_code rtems_message_queue_receive( buffer, size, wait, - timeout + timeout, + &lock_context ); - _Objects_Put( &the_message_queue->Object ); return _Message_queue_Translate_core_message_queue_return_code( executing->Wait.return_code ); diff --git a/cpukit/rtems/src/msgqsend.c b/cpukit/rtems/src/msgqsend.c index 34b7c29e7c..fb3979ed78 100644 --- a/cpukit/rtems/src/msgqsend.c +++ b/cpukit/rtems/src/msgqsend.c @@ -62,11 +62,16 @@ rtems_status_code rtems_message_queue_send( Message_queue_Control *the_message_queue; Objects_Locations location; CORE_message_queue_Status status; + ISR_lock_Context lock_context; if ( !buffer ) return RTEMS_INVALID_ADDRESS; - the_message_queue = _Message_queue_Get( id, &location ); + the_message_queue = _Message_queue_Get_interrupt_disable( + id, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -77,11 +82,10 @@ rtems_status_code rtems_message_queue_send( id, MESSAGE_QUEUE_MP_HANDLER, false, /* sender does not block */ - 0 /* no timeout */ + 0, /* no timeout */ + &lock_context ); - _Objects_Put( &the_message_queue->Object ); - /* * Since this API does not allow for blocking sends, we can directly * return the returned status. diff --git a/cpukit/rtems/src/msgqurgent.c b/cpukit/rtems/src/msgqurgent.c index 85a9d4f1b4..e6ae5efcf0 100644 --- a/cpukit/rtems/src/msgqurgent.c +++ b/cpukit/rtems/src/msgqurgent.c @@ -45,11 +45,16 @@ rtems_status_code rtems_message_queue_urgent( Message_queue_Control *the_message_queue; Objects_Locations location; CORE_message_queue_Status status; + ISR_lock_Context lock_context; if ( !buffer ) return RTEMS_INVALID_ADDRESS; - the_message_queue = _Message_queue_Get( id, &location ); + the_message_queue = _Message_queue_Get_interrupt_disable( + id, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -60,9 +65,9 @@ rtems_status_code rtems_message_queue_urgent( id, MESSAGE_QUEUE_MP_HANDLER, false, /* sender does not block */ - 0 /* no timeout */ + 0, /* no timeout */ + &lock_context ); - _Objects_Put( &the_message_queue->Object ); /* * Since this API does not allow for blocking sends, we can directly diff --git a/cpukit/score/include/rtems/score/coremsgimpl.h b/cpukit/score/include/rtems/score/coremsgimpl.h index 1f6796905b..51b5f3780f 100644 --- a/cpukit/score/include/rtems/score/coremsgimpl.h +++ b/cpukit/score/include/rtems/score/coremsgimpl.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -172,11 +173,13 @@ void _CORE_message_queue_Close( * number of messages flushed from the queue is returned. * * @param[in] the_message_queue points to the message queue to flush + * @param[in] lock_context The lock context of the interrupt disable. * * @retval This method returns the number of message pending messages flushed. */ uint32_t _CORE_message_queue_Flush( - CORE_message_queue_Control *the_message_queue + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context ); #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) @@ -215,6 +218,7 @@ uint32_t _CORE_message_queue_Flush( * a thread that is unblocked is actually a remote thread. * @param[out] count points to the variable that will contain the * number of tasks that are sent this message + * @param[in] lock_context The lock context of the interrupt disable. * @retval @a *count will contain the number of messages sent * @retval indication of the successful completion or reason for failure */ @@ -224,7 +228,8 @@ CORE_message_queue_Status _CORE_message_queue_Broadcast( size_t size, Objects_Id id, CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, - uint32_t *count + uint32_t *count, + ISR_lock_Context *lock_context ); /** @@ -250,6 +255,7 @@ CORE_message_queue_Status _CORE_message_queue_Broadcast( * if the message queue is full. * @param[in] timeout is the maximum number of clock ticks that the calling * thread is willing to block if the message queue is full. + * @param[in] lock_context The lock context of the interrupt disable. * @retval indication of the successful completion or reason for failure */ CORE_message_queue_Status _CORE_message_queue_Submit( @@ -261,7 +267,8 @@ CORE_message_queue_Status _CORE_message_queue_Submit( CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, CORE_message_queue_Submit_types submit_type, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -287,6 +294,7 @@ CORE_message_queue_Status _CORE_message_queue_Submit( * if the message queue is empty. * @param[in] timeout is the maximum number of clock ticks that the calling * thread is willing to block if the message queue is empty. + * @param[in] lock_context The lock context of the interrupt disable. * * @retval indication of the successful completion or reason for failure. * On success, the location pointed to @a size_p will contain the @@ -305,7 +313,8 @@ void _CORE_message_queue_Seize( void *buffer, size_t *size_p, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -338,8 +347,9 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Send( size_t size, Objects_Id id, CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, - bool wait, - Watchdog_Interval timeout + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { return _CORE_message_queue_Submit( @@ -351,7 +361,8 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Send( api_message_queue_mp_support, CORE_MESSAGE_QUEUE_SEND_REQUEST, wait, /* sender may block */ - timeout /* timeout interval */ + timeout, /* timeout interval */ + lock_context ); } @@ -364,8 +375,9 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Urgent( size_t size, Objects_Id id, CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, - bool wait, - Watchdog_Interval timeout + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { return _CORE_message_queue_Submit( @@ -377,10 +389,46 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Urgent( api_message_queue_mp_support, CORE_MESSAGE_QUEUE_URGENT_REQUEST, wait, /* sender may block */ - timeout /* timeout interval */ + timeout, /* timeout interval */ + lock_context ); } +RTEMS_INLINE_ROUTINE void _CORE_message_queue_Acquire( + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Acquire( &the_message_queue->Wait_queue, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _CORE_message_queue_Acquire_critical( + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Acquire_critical( &the_message_queue->Wait_queue, lock_context ); + + #if defined(RTEMS_MULTIPROCESSING) + /* + * In case RTEMS_MULTIPROCESSING is enabled, then we have to prevent + * deletion of the executing thread after the thread queue operations. + */ + _Thread_Dispatch_disable(); + #endif +} + +RTEMS_INLINE_ROUTINE void _CORE_message_queue_Release( + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Release( &the_message_queue->Wait_queue, lock_context ); + #if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_enable( _Per_CPU_Get() ); + #endif +} + /** * This routine copies the contents of the source message buffer * to the destination message buffer. @@ -404,7 +452,7 @@ _CORE_message_queue_Allocate_message_buffer ( ) { return (CORE_message_queue_Buffer_control *) - _Chain_Get( &the_message_queue->Inactive_messages ); + _Chain_Get_unprotected( &the_message_queue->Inactive_messages ); } /** @@ -416,7 +464,7 @@ RTEMS_INLINE_ROUTINE void _CORE_message_queue_Free_message_buffer ( CORE_message_queue_Buffer_control *the_message ) { - _Chain_Append( &the_message_queue->Inactive_messages, &the_message->Node ); + _Chain_Append_unprotected( &the_message_queue->Inactive_messages, &the_message->Node ); } /** @@ -510,6 +558,55 @@ RTEMS_INLINE_ROUTINE bool _CORE_message_queue_Is_priority( the_message_queue, the_handler, the_argument ) #endif +RTEMS_INLINE_ROUTINE Thread_Control *_CORE_message_queue_Dequeue_receiver( + CORE_message_queue_Control *the_message_queue, + const void *buffer, + size_t size, + CORE_message_queue_Submit_types submit_type, + ISR_lock_Context *lock_context +) +{ + Thread_Control *the_thread; + + /* + * If there are pending messages, then there can't be threads + * waiting for us to send them a message. + * + * NOTE: This check is critical because threads can block on + * send and receive and this ensures that we are broadcasting + * the message to threads waiting to receive -- not to send. + */ + if ( the_message_queue->number_of_pending_messages != 0 ) { + return NULL; + } + + /* + * There must be no pending messages if there is a thread waiting to + * receive a message. + */ + the_thread = _Thread_queue_First_locked( &the_message_queue->Wait_queue ); + if ( the_thread == NULL ) { + return NULL; + } + + *(size_t *) the_thread->Wait.return_argument = size; + the_thread->Wait.count = (uint32_t) submit_type; + + _CORE_message_queue_Copy_buffer( + buffer, + the_thread->Wait.return_argument_second.mutable_object, + size + ); + + _Thread_queue_Extract_critical( + &the_message_queue->Wait_queue, + the_thread, + lock_context + ); + + return the_thread; +} + /** @} */ #ifdef __cplusplus diff --git a/cpukit/score/src/coremsgbroadcast.c b/cpukit/score/src/coremsgbroadcast.c index ff9f3ec220..3ee587ccfb 100644 --- a/cpukit/score/src/coremsgbroadcast.c +++ b/cpukit/score/src/coremsgbroadcast.c @@ -20,7 +20,6 @@ #include #include -#include CORE_message_queue_Status _CORE_message_queue_Broadcast( CORE_message_queue_Control *the_message_queue, @@ -33,55 +32,45 @@ CORE_message_queue_Status _CORE_message_queue_Broadcast( Objects_Id id __attribute__((unused)), CORE_message_queue_API_mp_support_callout api_message_queue_mp_support __attribute__((unused)), #endif - uint32_t *count + uint32_t *count, + ISR_lock_Context *lock_context ) { - Thread_Control *the_thread; - uint32_t number_broadcasted; - Thread_Wait_information *waitp; + Thread_Control *the_thread; + uint32_t number_broadcasted; if ( size > the_message_queue->maximum_message_size ) { + _ISR_lock_ISR_enable( lock_context ); return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE; } - /* - * If there are pending messages, then there can't be threads - * waiting for us to send them a message. - * - * NOTE: This check is critical because threads can block on - * send and receive and this ensures that we are broadcasting - * the message to threads waiting to receive -- not to send. - */ + number_broadcasted = 0; - if ( the_message_queue->number_of_pending_messages != 0 ) { - *count = 0; - return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; - } + _CORE_message_queue_Acquire_critical( the_message_queue, lock_context ); - /* - * There must be no pending messages if there is a thread waiting to - * receive a message. - */ - number_broadcasted = 0; - while ((the_thread = - _Thread_queue_Dequeue(&the_message_queue->Wait_queue))) { - waitp = &the_thread->Wait; + while ( + ( the_thread = + _CORE_message_queue_Dequeue_receiver( + the_message_queue, + buffer, + size, + 0, + lock_context + ) + ) + ) { number_broadcasted += 1; - _CORE_message_queue_Copy_buffer( - buffer, - waitp->return_argument_second.mutable_object, - size - ); +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_message_queue_mp_support) ( the_thread, id ); +#endif - *(size_t *) the_thread->Wait.return_argument = size; + _CORE_message_queue_Acquire( the_message_queue, lock_context ); + } - #if defined(RTEMS_MULTIPROCESSING) - if ( !_Objects_Is_local_id( the_thread->Object.id ) ) - (*api_message_queue_mp_support) ( the_thread, id ); - #endif + _CORE_message_queue_Release( the_message_queue, lock_context ); - } *count = number_broadcasted; return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; } diff --git a/cpukit/score/src/coremsgclose.c b/cpukit/score/src/coremsgclose.c index d808a4efbc..e0d370d512 100644 --- a/cpukit/score/src/coremsgclose.c +++ b/cpukit/score/src/coremsgclose.c @@ -18,11 +18,7 @@ #include "config.h" #endif -#include -#include -#include #include -#include #include void _CORE_message_queue_Close( @@ -31,6 +27,7 @@ void _CORE_message_queue_Close( uint32_t status ) { + ISR_lock_Context lock_context; /* * This will flush blocked threads whether they were blocked on @@ -49,7 +46,8 @@ void _CORE_message_queue_Close( * the flush satisfying any blocked senders as a side-effect. */ - (void) _CORE_message_queue_Flush( the_message_queue ); + _ISR_lock_ISR_disable( &lock_context ); + (void) _CORE_message_queue_Flush( the_message_queue, &lock_context ); (void) _Workspace_Free( the_message_queue->message_buffers ); diff --git a/cpukit/score/src/coremsgflush.c b/cpukit/score/src/coremsgflush.c index 05683f0327..f67dcf28eb 100644 --- a/cpukit/score/src/coremsgflush.c +++ b/cpukit/score/src/coremsgflush.c @@ -20,13 +20,12 @@ #endif #include -#include uint32_t _CORE_message_queue_Flush( - CORE_message_queue_Control *the_message_queue + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context ) { - ISR_Level level; Chain_Node *inactive_head; Chain_Node *inactive_first; Chain_Node *message_queue_first; @@ -60,7 +59,7 @@ uint32_t _CORE_message_queue_Flush( * fixed execution time that only deals with pending messages. */ - _ISR_Disable( level ); + _CORE_message_queue_Acquire_critical( the_message_queue, lock_context ); count = the_message_queue->number_of_pending_messages; if ( count != 0 ) { @@ -79,6 +78,6 @@ uint32_t _CORE_message_queue_Flush( _Chain_Initialize_empty( &the_message_queue->Pending_messages ); } - _ISR_Enable( level ); + _CORE_message_queue_Release( the_message_queue, lock_context ); return count; } diff --git a/cpukit/score/src/coremsginsert.c b/cpukit/score/src/coremsginsert.c index 28407bae98..0a73af8c71 100644 --- a/cpukit/score/src/coremsginsert.c +++ b/cpukit/score/src/coremsginsert.c @@ -19,7 +19,6 @@ #endif #include -#include #if defined(RTEMS_SCORE_COREMSG_ENABLE_MESSAGE_PRIORITY) static bool _CORE_message_queue_Order( @@ -45,7 +44,6 @@ void _CORE_message_queue_Insert_message( ) { Chain_Control *pending_messages; - ISR_Level level; #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION) bool notify; #endif @@ -53,8 +51,6 @@ void _CORE_message_queue_Insert_message( _CORE_message_queue_Set_message_priority( the_message, submit_type ); pending_messages = &the_message_queue->Pending_messages; - _ISR_Disable( level ); - #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION) notify = ( the_message_queue->number_of_pending_messages == 0 ); #endif @@ -74,8 +70,6 @@ void _CORE_message_queue_Insert_message( _Chain_Prepend_unprotected( pending_messages, &the_message->Node ); } - _ISR_Enable( level ); - #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION) /* * According to POSIX, does this happen before or after the message diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c index ec6cf8c52e..0d1c36fe47 100644 --- a/cpukit/score/src/coremsgseize.c +++ b/cpukit/score/src/coremsgseize.c @@ -33,18 +33,17 @@ void _CORE_message_queue_Seize( void *buffer, size_t *size_p, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { - ISR_lock_Context lock_context; CORE_message_queue_Buffer_control *the_message; executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; - _Thread_queue_Acquire( &the_message_queue->Wait_queue, &lock_context ); + _CORE_message_queue_Acquire_critical( the_message_queue, lock_context ); the_message = _CORE_message_queue_Get_pending_message( the_message_queue ); if ( the_message != NULL ) { the_message_queue->number_of_pending_messages -= 1; - _Thread_queue_Release( &the_message_queue->Wait_queue, &lock_context ); *size_p = the_message->Contents.size; executing->Wait.count = @@ -61,6 +60,7 @@ void _CORE_message_queue_Seize( * So return immediately. */ _CORE_message_queue_Free_message_buffer(the_message_queue, the_message); + _CORE_message_queue_Release( the_message_queue, lock_context ); return; #else { @@ -73,12 +73,15 @@ void _CORE_message_queue_Seize( * NOTE: If we note that the queue was not full before this receive, * then we can avoid this dequeue. */ - the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue ); - if ( !the_thread ) { + the_thread = _Thread_queue_First_locked( + &the_message_queue->Wait_queue + ); + if ( the_thread == NULL ) { _CORE_message_queue_Free_message_buffer( the_message_queue, the_message ); + _CORE_message_queue_Release( the_message_queue, lock_context ); return; } @@ -103,13 +106,21 @@ void _CORE_message_queue_Seize( the_message, _CORE_message_queue_Get_message_priority( the_message ) ); + _Thread_queue_Extract_critical( + &the_message_queue->Wait_queue, + the_thread, + lock_context + ); + #if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_enable( _Per_CPU_Get() ); + #endif return; } #endif } if ( !wait ) { - _Thread_queue_Release( &the_message_queue->Wait_queue, &lock_context ); + _CORE_message_queue_Release( the_message_queue, lock_context ); executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT; return; } @@ -125,6 +136,9 @@ void _CORE_message_queue_Seize( STATES_WAITING_FOR_MESSAGE, timeout, CORE_MESSAGE_QUEUE_STATUS_TIMEOUT, - &lock_context + lock_context ); + #if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_enable( _Per_CPU_Get() ); + #endif } diff --git a/cpukit/score/src/coremsgsubmit.c b/cpukit/score/src/coremsgsubmit.c index 0d0965ffbf..37f857917c 100644 --- a/cpukit/score/src/coremsgsubmit.c +++ b/cpukit/score/src/coremsgsubmit.c @@ -38,36 +38,39 @@ CORE_message_queue_Status _CORE_message_queue_Submit( #endif CORE_message_queue_Submit_types submit_type, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { - CORE_message_queue_Buffer_control *the_message; - Thread_Control *the_thread; + CORE_message_queue_Buffer_control *the_message; + Thread_Control *the_thread; if ( size > the_message_queue->maximum_message_size ) { + _ISR_lock_ISR_enable( lock_context ); return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE; } + _CORE_message_queue_Acquire_critical( the_message_queue, lock_context ); + /* * Is there a thread currently waiting on this message queue? */ - if ( the_message_queue->number_of_pending_messages == 0 ) { - the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue ); - if ( the_thread ) { - _CORE_message_queue_Copy_buffer( - buffer, - the_thread->Wait.return_argument_second.mutable_object, - size - ); - *(size_t *) the_thread->Wait.return_argument = size; - the_thread->Wait.count = (uint32_t) submit_type; - - #if defined(RTEMS_MULTIPROCESSING) - if ( !_Objects_Is_local_id( the_thread->Object.id ) ) - (*api_message_queue_mp_support) ( the_thread, id ); - #endif - return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; - } + + the_thread = _CORE_message_queue_Dequeue_receiver( + the_message_queue, + buffer, + size, + submit_type, + lock_context + ); + if ( the_thread != NULL ) { + #if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_message_queue_mp_support) ( the_thread, id ); + + _Thread_Dispatch_enable( _Per_CPU_Get() ); + #endif + return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; } /* @@ -77,23 +80,25 @@ CORE_message_queue_Status _CORE_message_queue_Submit( the_message = _CORE_message_queue_Allocate_message_buffer( the_message_queue ); if ( the_message ) { + the_message->Contents.size = size; + _CORE_message_queue_Set_message_priority( the_message, submit_type ); _CORE_message_queue_Copy_buffer( buffer, the_message->Contents.buffer, size ); - the_message->Contents.size = size; - _CORE_message_queue_Set_message_priority( the_message, submit_type ); _CORE_message_queue_Insert_message( the_message_queue, the_message, submit_type ); + _CORE_message_queue_Release( the_message_queue, lock_context ); return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; } #if !defined(RTEMS_SCORE_COREMSG_ENABLE_BLOCKING_SEND) + _CORE_message_queue_Release( the_message_queue, lock_context ); return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY; #else /* @@ -102,6 +107,7 @@ CORE_message_queue_Status _CORE_message_queue_Submit( * on the queue. */ if ( !wait ) { + _CORE_message_queue_Release( the_message_queue, lock_context ); return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY; } @@ -110,6 +116,7 @@ CORE_message_queue_Status _CORE_message_queue_Submit( * deadly to block in an ISR. */ if ( _ISR_Is_in_progress() ) { + _CORE_message_queue_Release( the_message_queue, lock_context ); return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED; } @@ -119,20 +126,22 @@ CORE_message_queue_Status _CORE_message_queue_Submit( * it as a variable. Doing this emphasizes how dangerous it * would be to use this variable prior to here. */ - { - executing->Wait.id = id; - executing->Wait.return_argument_second.immutable_object = buffer; - executing->Wait.option = (uint32_t) size; - executing->Wait.count = submit_type; - - _Thread_queue_Enqueue( - &the_message_queue->Wait_queue, - executing, - STATES_WAITING_FOR_MESSAGE, - timeout, - CORE_MESSAGE_QUEUE_STATUS_TIMEOUT - ); - } + executing->Wait.id = id; + executing->Wait.return_argument_second.immutable_object = buffer; + executing->Wait.option = (uint32_t) size; + executing->Wait.count = submit_type; + + _Thread_queue_Enqueue_critical( + &the_message_queue->Wait_queue, + executing, + STATES_WAITING_FOR_MESSAGE, + timeout, + CORE_MESSAGE_QUEUE_STATUS_TIMEOUT, + lock_context + ); + #if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_enable( _Per_CPU_Get() ); + #endif return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT; #endif diff --git a/doc/user/msg.t b/doc/user/msg.t index f58d677150..eb3cb3561a 100644 --- a/doc/user/msg.t +++ b/doc/user/msg.t @@ -50,7 +50,10 @@ wait for a message to arrive at a queue. Also, a task may poll a queue for the arrival of a message. The maximum length message which can be sent is set -on a per message queue basis. +on a per message queue basis. The message content must be copied in general +to/from an internal buffer of the message queue or directly to a peer in +certain cases. This copy operation is performed with interrupts disabled. So +it is advisable to keep the messages as short as possible. @subsection Building a Message Queue Attribute Set -- cgit v1.2.3 From e76c517d0726f91447e0e2c3ba14c00896456e89 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 1 May 2015 20:52:51 +0200 Subject: score: Fine grained locking for semaphores Update #2273. --- cpukit/posix/include/rtems/posix/semaphoreimpl.h | 14 ++++++++++ cpukit/posix/src/sempost.c | 13 ++++++--- cpukit/rtems/src/semobtain.c | 9 +++---- cpukit/rtems/src/semrelease.c | 19 +++++++++---- cpukit/score/include/rtems/score/coresemimpl.h | 13 ++++----- cpukit/score/src/coresemsurrender.c | 34 ++++++++++++++++-------- cpukit/score/src/mpci.c | 7 ++--- 7 files changed, 75 insertions(+), 34 deletions(-) diff --git a/cpukit/posix/include/rtems/posix/semaphoreimpl.h b/cpukit/posix/include/rtems/posix/semaphoreimpl.h index 783289aa44..eeea51c488 100644 --- a/cpukit/posix/include/rtems/posix/semaphoreimpl.h +++ b/cpukit/posix/include/rtems/posix/semaphoreimpl.h @@ -89,6 +89,20 @@ RTEMS_INLINE_ROUTINE POSIX_Semaphore_Control *_POSIX_Semaphore_Get ( _Objects_Get( &_POSIX_Semaphore_Information, (Objects_Id)*id, location ); } +RTEMS_INLINE_ROUTINE POSIX_Semaphore_Control * +_POSIX_Semaphore_Get_interrupt_disable( + sem_t *id, + Objects_Locations *location, + ISR_lock_Context *lock_context +) +{ + return (POSIX_Semaphore_Control *) _Objects_Get_isr_disable( + &_POSIX_Semaphore_Information, + (Objects_Id)*id, + location, + lock_context + ); +} /** * @brief POSIX Semaphore Create Support diff --git a/cpukit/posix/src/sempost.c b/cpukit/posix/src/sempost.c index f139c9ab67..9c8c673ddb 100644 --- a/cpukit/posix/src/sempost.c +++ b/cpukit/posix/src/sempost.c @@ -37,8 +37,13 @@ int sem_post( { POSIX_Semaphore_Control *the_semaphore; Objects_Locations location; + ISR_lock_Context lock_context; - the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + the_semaphore = _POSIX_Semaphore_Get_interrupt_disable( + sem, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -46,12 +51,12 @@ int sem_post( &the_semaphore->Semaphore, the_semaphore->Object.id, #if defined(RTEMS_MULTIPROCESSING) - NULL /* POSIX Semaphores are local only */ + NULL, /* POSIX Semaphores are local only */ #else - NULL + NULL, #endif + &lock_context ); - _Objects_Put( &the_semaphore->Object ); return 0; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index 0edac96264..ca13bea080 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -56,10 +56,10 @@ rtems_status_code rtems_semaphore_obtain( attribute_set = the_semaphore->attribute_set; wait = !_Options_Is_no_wait( option_set ); #if defined(RTEMS_SMP) - _Thread_Disable_dispatch(); if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { MRSP_Status mrsp_status; + _Thread_Disable_dispatch(); _ISR_lock_ISR_enable( &lock_context ); mrsp_status = _MRSP_Obtain( &the_semaphore->Core_control.mrsp, @@ -73,6 +73,9 @@ rtems_status_code rtems_semaphore_obtain( } else #endif if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { +#if defined(RTEMS_SMP) + _Thread_Disable_dispatch(); +#endif _CORE_mutex_Seize( &the_semaphore->Core_control.mutex, executing, @@ -98,10 +101,6 @@ rtems_status_code rtems_semaphore_obtain( timeout, &lock_context ); -#if defined(RTEMS_SMP) - _Thread_Enable_dispatch(); -#endif - _Objects_Put_for_get_isr_disable( &the_semaphore->Object ); return _Semaphore_Translate_core_semaphore_return_code( executing->Wait.return_code ); diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c index 37a05b2507..1f0581eec1 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -62,37 +62,46 @@ rtems_status_code rtems_semaphore_release( CORE_mutex_Status mutex_status; CORE_semaphore_Status semaphore_status; rtems_attribute attribute_set; + ISR_lock_Context lock_context; - the_semaphore = _Semaphore_Get( id, &location ); + the_semaphore = _Semaphore_Get_interrupt_disable( + id, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: attribute_set = the_semaphore->attribute_set; #if defined(RTEMS_SMP) if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + _Thread_Disable_dispatch(); + _ISR_lock_ISR_enable( &lock_context ); MRSP_Status mrsp_status = _MRSP_Release( &the_semaphore->Core_control.mrsp, _Thread_Get_executing() ); - _Objects_Put( &the_semaphore->Object ); + _Thread_Enable_dispatch(); return _Semaphore_Translate_MRSP_status_code( mrsp_status ); } else #endif if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { + _Thread_Disable_dispatch(); + _ISR_lock_ISR_enable( &lock_context ); mutex_status = _CORE_mutex_Surrender( &the_semaphore->Core_control.mutex, id, MUTEX_MP_SUPPORT ); - _Objects_Put( &the_semaphore->Object ); + _Thread_Enable_dispatch(); return _Semaphore_Translate_core_mutex_return_code( mutex_status ); } else { semaphore_status = _CORE_semaphore_Surrender( &the_semaphore->Core_control.semaphore, id, - MUTEX_MP_SUPPORT + MUTEX_MP_SUPPORT, + &lock_context ); - _Objects_Put( &the_semaphore->Object ); return _Semaphore_Translate_core_semaphore_return_code( semaphore_status ); } diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index 3e1d481ab8..75851ee0d1 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -141,13 +141,16 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Destroy( * with this instance of a SuperCore Semaphore * @param[in] api_semaphore_mp_support is the routine to invoke if the * thread unblocked is remote + * @param[in] lock_context is a temporary variable used to contain the ISR + * disable level cookie * * @retval an indication of whether the routine succeeded or failed */ CORE_semaphore_Status _CORE_semaphore_Surrender( CORE_semaphore_Control *the_semaphore, Objects_Id id, - CORE_semaphore_API_mp_support_callout api_semaphore_mp_support + CORE_semaphore_API_mp_support_callout api_semaphore_mp_support, + ISR_lock_Context *lock_context ); /** @@ -228,21 +231,20 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Seize_isr_disable( /* disabled when you get here */ executing->Wait.return_code = CORE_SEMAPHORE_STATUS_SUCCESSFUL; + _Thread_queue_Acquire_critical( &the_semaphore->Wait_queue, lock_context ); if ( the_semaphore->count != 0 ) { the_semaphore->count -= 1; - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_semaphore->Wait_queue, lock_context ); return; } if ( !wait ) { - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_semaphore->Wait_queue, lock_context ); executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT; return; } - _Thread_Disable_dispatch(); executing->Wait.id = id; - _Thread_queue_Acquire_critical( &the_semaphore->Wait_queue, lock_context ); _Thread_queue_Enqueue_critical( &the_semaphore->Wait_queue, executing, @@ -251,7 +253,6 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Seize_isr_disable( CORE_SEMAPHORE_TIMEOUT, lock_context ); - _Thread_Enable_dispatch(); } /** @} */ diff --git a/cpukit/score/src/coresemsurrender.c b/cpukit/score/src/coresemsurrender.c index 58ba6a3fdf..9b3d8fd4be 100644 --- a/cpukit/score/src/coresemsurrender.c +++ b/cpukit/score/src/coresemsurrender.c @@ -20,34 +20,46 @@ #endif #include -#include CORE_semaphore_Status _CORE_semaphore_Surrender( CORE_semaphore_Control *the_semaphore, Objects_Id id, - CORE_semaphore_API_mp_support_callout api_semaphore_mp_support + CORE_semaphore_API_mp_support_callout api_semaphore_mp_support, + ISR_lock_Context *lock_context ) { Thread_Control *the_thread; - ISR_Level level; CORE_semaphore_Status status; status = CORE_SEMAPHORE_STATUS_SUCCESSFUL; - if ( (the_thread = _Thread_queue_Dequeue(&the_semaphore->Wait_queue)) ) { + _Thread_queue_Acquire_critical( &the_semaphore->Wait_queue, lock_context ); + + the_thread = _Thread_queue_First_locked( &the_semaphore->Wait_queue ); + if ( the_thread != NULL ) { +#if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_disable(); +#endif + + _Thread_queue_Extract_critical( + &the_semaphore->Wait_queue, + the_thread, + lock_context + ); #if defined(RTEMS_MULTIPROCESSING) if ( !_Objects_Is_local_id( the_thread->Object.id ) ) (*api_semaphore_mp_support) ( the_thread, id ); -#endif + _Thread_Dispatch_enable( _Per_CPU_Get() ); +#endif } else { - _ISR_Disable( level ); - if ( the_semaphore->count < the_semaphore->Attributes.maximum_count ) - the_semaphore->count += 1; - else - status = CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED; - _ISR_Enable( level ); + if ( the_semaphore->count < the_semaphore->Attributes.maximum_count ) + the_semaphore->count += 1; + else + status = CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED; + + _Thread_queue_Release( &the_semaphore->Wait_queue, lock_context ); } return status; diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 7fd77f7597..6b3bc7fbd8 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -329,9 +329,10 @@ Thread _MPCI_Receive_server( void _MPCI_Announce ( void ) { - _Thread_Disable_dispatch(); - (void) _CORE_semaphore_Surrender( &_MPCI_Semaphore, 0, 0 ); - _Thread_Enable_dispatch(); + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable( &lock_context ); + (void) _CORE_semaphore_Surrender( &_MPCI_Semaphore, 0, 0, &lock_context ); } void _MPCI_Internal_packets_Send_process_packet ( -- cgit v1.2.3 From cfa5aabc786c27887f219b92c1a6566020d96f1a Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sat, 2 May 2015 14:02:20 +0200 Subject: score: Delete _CORE_semaphore_Seize() Rename _CORE_semaphore_Seize_isr_disable() to _CORE_semaphore_Seize(). --- cpukit/posix/src/semaphorewaitsupp.c | 11 ++-- cpukit/rtems/src/semobtain.c | 2 +- cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/coresemimpl.h | 30 +---------- cpukit/score/src/coresemseize.c | 72 -------------------------- cpukit/score/src/mpci.c | 7 +-- 6 files changed, 15 insertions(+), 109 deletions(-) delete mode 100644 cpukit/score/src/coresemseize.c diff --git a/cpukit/posix/src/semaphorewaitsupp.c b/cpukit/posix/src/semaphorewaitsupp.c index cd572c4017..8b36561983 100644 --- a/cpukit/posix/src/semaphorewaitsupp.c +++ b/cpukit/posix/src/semaphorewaitsupp.c @@ -40,8 +40,13 @@ int _POSIX_Semaphore_Wait_support( POSIX_Semaphore_Control *the_semaphore; Objects_Locations location; Thread_Control *executing; + ISR_lock_Context lock_context; - the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + the_semaphore = _POSIX_Semaphore_Get_interrupt_disable( + sem, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -51,9 +56,9 @@ int _POSIX_Semaphore_Wait_support( executing, the_semaphore->Object.id, blocking, - timeout + timeout, + &lock_context ); - _Objects_Put( &the_semaphore->Object ); if ( !executing->Wait.return_code ) return 0; diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index ca13bea080..46d1b82f33 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -93,7 +93,7 @@ rtems_status_code rtems_semaphore_obtain( } /* must be a counting semaphore */ - _CORE_semaphore_Seize_isr_disable( + _CORE_semaphore_Seize( &the_semaphore->Core_control.semaphore, executing, id, diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 6d4414c430..d8ec8e113b 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -177,7 +177,7 @@ libscore_a_SOURCES += src/corerwlock.c src/corerwlockobtainread.c \ endif ## CORE_SEMAPHORE_C_FILES -libscore_a_SOURCES += src/coresem.c src/coresemflush.c src/coresemseize.c \ +libscore_a_SOURCES += src/coresem.c src/coresemflush.c \ src/coresemsurrender.c ## CORE_SPINLOCK_C_FILES diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index 75851ee0d1..7e967ed488 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -33,10 +33,6 @@ extern "C" { */ /**@{**/ -#if defined(RTEMS_POSIX_API) || defined(RTEMS_MULTIPROCESSING) - #define RTEMS_SCORE_CORESEM_ENABLE_SEIZE_BODY -#endif - /** * Core Semaphore handler return statuses. */ @@ -105,30 +101,6 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Destroy( _Thread_queue_Destroy( &the_semaphore->Wait_queue ); } -#if defined(RTEMS_SCORE_CORESEM_ENABLE_SEIZE_BODY) - /** - * This routine attempts to receive a unit from @a the_semaphore. - * If a unit is available or if the wait flag is false, then the routine - * returns. Otherwise, the calling task is blocked until a unit becomes - * available. - * - * @param[in] the_semaphore is the semaphore to seize - * @param[in,out] executing The currently executing thread. - * @param[in] id is the Id of the API level Semaphore object associated - * with this instance of a SuperCore Semaphore - * @param[in] wait indicates if the caller is willing to block - * @param[in] timeout is the number of ticks the calling thread is willing - * to wait if @a wait is true. - */ - void _CORE_semaphore_Seize( - CORE_semaphore_Control *the_semaphore, - Thread_Control *executing, - Objects_Id id, - bool wait, - Watchdog_Interval timeout - ); -#endif - /** * @brief Surrender a unit to a semaphore. * @@ -219,7 +191,7 @@ RTEMS_INLINE_ROUTINE uint32_t _CORE_semaphore_Get_count( * * @note There is currently no MACRO version of this routine. */ -RTEMS_INLINE_ROUTINE void _CORE_semaphore_Seize_isr_disable( +RTEMS_INLINE_ROUTINE void _CORE_semaphore_Seize( CORE_semaphore_Control *the_semaphore, Thread_Control *executing, Objects_Id id, diff --git a/cpukit/score/src/coresemseize.c b/cpukit/score/src/coresemseize.c deleted file mode 100644 index 6ecf2c4c8f..0000000000 --- a/cpukit/score/src/coresemseize.c +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file - * - * @brief Core Semaphore Seize - * - * @ingroup ScoreSemaphore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -#if defined(RTEMS_SCORE_CORESEM_ENABLE_SEIZE_BODY) - -void _CORE_semaphore_Seize( - CORE_semaphore_Control *the_semaphore, - Thread_Control *executing, - Objects_Id id, - bool wait, - Watchdog_Interval timeout -) -{ - ISR_lock_Context lock_context; - - executing->Wait.return_code = CORE_SEMAPHORE_STATUS_SUCCESSFUL; - _Thread_queue_Acquire( &the_semaphore->Wait_queue, &lock_context ); - if ( the_semaphore->count != 0 ) { - the_semaphore->count -= 1; - _Thread_queue_Release( &the_semaphore->Wait_queue, &lock_context ); - return; - } - - /* - * If the semaphore was not available and the caller was not willing - * to block, then return immediately with a status indicating that - * the semaphore was not available and the caller never blocked. - */ - if ( !wait ) { - _Thread_queue_Release( &the_semaphore->Wait_queue, &lock_context ); - executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT; - return; - } - - /* - * If the semaphore is not available and the caller is willing to - * block, then we now block the caller with optional timeout. - */ - executing->Wait.id = id; - _Thread_queue_Enqueue_critical( - &the_semaphore->Wait_queue, - executing, - STATES_WAITING_FOR_SEMAPHORE, - timeout, - CORE_SEMAPHORE_TIMEOUT, - &lock_context - ); -} -#endif diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 6b3bc7fbd8..2b1f6fff44 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -283,6 +283,7 @@ Thread _MPCI_Receive_server( MP_packet_Prefix *the_packet; MPCI_Packet_processor the_function; Thread_Control *executing; + ISR_lock_Context lock_context; executing = _Thread_Get_executing(); @@ -290,15 +291,15 @@ Thread _MPCI_Receive_server( executing->receive_packet = NULL; - _Thread_Disable_dispatch(); + _ISR_lock_ISR_disable( &lock_context ); _CORE_semaphore_Seize( &_MPCI_Semaphore, executing, 0, true, - WATCHDOG_NO_TIMEOUT + WATCHDOG_NO_TIMEOUT, + &lock_context ); - _Thread_Enable_dispatch(); for ( ; ; ) { the_packet = _MPCI_Receive_packet(); -- cgit v1.2.3 From b76dd97990844ad0a0ff6cefadd433b681805a35 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sat, 2 May 2015 14:04:21 +0200 Subject: score: Inline _CORE_semaphore_Flush() --- cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/coresemimpl.h | 11 ++++++-- cpukit/score/src/coresemflush.c | 39 -------------------------- 3 files changed, 10 insertions(+), 42 deletions(-) delete mode 100644 cpukit/score/src/coresemflush.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index d8ec8e113b..58673bb188 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -177,7 +177,7 @@ libscore_a_SOURCES += src/corerwlock.c src/corerwlockobtainread.c \ endif ## CORE_SEMAPHORE_C_FILES -libscore_a_SOURCES += src/coresem.c src/coresemflush.c \ +libscore_a_SOURCES += src/coresem.c \ src/coresemsurrender.c ## CORE_SPINLOCK_C_FILES diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index 7e967ed488..dcea1a3737 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -140,11 +140,18 @@ CORE_semaphore_Status _CORE_semaphore_Surrender( * thread unblocked is remote * @param[in] status is the status to be returned to the unblocked thread */ -void _CORE_semaphore_Flush( +RTEMS_INLINE_ROUTINE void _CORE_semaphore_Flush( CORE_semaphore_Control *the_semaphore, Thread_queue_Flush_callout remote_extract_callout, uint32_t status -); +) +{ + _Thread_queue_Flush( + &the_semaphore->Wait_queue, + remote_extract_callout, + status + ); +} /** * This function returns true if the priority attribute is diff --git a/cpukit/score/src/coresemflush.c b/cpukit/score/src/coresemflush.c deleted file mode 100644 index 1db0db926b..0000000000 --- a/cpukit/score/src/coresemflush.c +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file - * - * @brief Core Semaphore Flush - * @ingroup ScoreSemaphore - */ - -/* - * 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 -#include -#include -#include - -void _CORE_semaphore_Flush( - CORE_semaphore_Control *the_semaphore, - Thread_queue_Flush_callout remote_extract_callout, - uint32_t status -) -{ - - _Thread_queue_Flush( - &the_semaphore->Wait_queue, - remote_extract_callout, - status - ); - -} -- cgit v1.2.3 From d12b3135232ae3a70a8af66917dc7986fdd309e8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sat, 2 May 2015 14:06:38 +0200 Subject: score: Inline _CORE_semaphore_Surrender() --- cpukit/score/Makefile.am | 3 +- cpukit/score/include/rtems/score/coresemimpl.h | 42 +++++++++++++++- cpukit/score/src/coresemsurrender.c | 66 -------------------------- 3 files changed, 41 insertions(+), 70 deletions(-) delete mode 100644 cpukit/score/src/coresemsurrender.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 58673bb188..cede673bb6 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -177,8 +177,7 @@ libscore_a_SOURCES += src/corerwlock.c src/corerwlockobtainread.c \ endif ## CORE_SEMAPHORE_C_FILES -libscore_a_SOURCES += src/coresem.c \ - src/coresemsurrender.c +libscore_a_SOURCES += src/coresem.c ## CORE_SPINLOCK_C_FILES if HAS_PTHREADS diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index dcea1a3737..da57ad1dd4 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -20,6 +20,7 @@ #define _RTEMS_SCORE_CORESEMIMPL_H #include +#include #include #include #include @@ -118,12 +119,49 @@ RTEMS_INLINE_ROUTINE void _CORE_semaphore_Destroy( * * @retval an indication of whether the routine succeeded or failed */ -CORE_semaphore_Status _CORE_semaphore_Surrender( +RTEMS_INLINE_ROUTINE CORE_semaphore_Status _CORE_semaphore_Surrender( CORE_semaphore_Control *the_semaphore, Objects_Id id, CORE_semaphore_API_mp_support_callout api_semaphore_mp_support, ISR_lock_Context *lock_context -); +) +{ + Thread_Control *the_thread; + CORE_semaphore_Status status; + + status = CORE_SEMAPHORE_STATUS_SUCCESSFUL; + + _Thread_queue_Acquire_critical( &the_semaphore->Wait_queue, lock_context ); + + the_thread = _Thread_queue_First_locked( &the_semaphore->Wait_queue ); + if ( the_thread != NULL ) { +#if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_disable(); +#endif + + _Thread_queue_Extract_critical( + &the_semaphore->Wait_queue, + the_thread, + lock_context + ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_semaphore_mp_support) ( the_thread, id ); + + _Thread_Dispatch_enable( _Per_CPU_Get() ); +#endif + } else { + if ( the_semaphore->count < the_semaphore->Attributes.maximum_count ) + the_semaphore->count += 1; + else + status = CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED; + + _Thread_queue_Release( &the_semaphore->Wait_queue, lock_context ); + } + + return status; +} /** * @brief Core semaphore flush. diff --git a/cpukit/score/src/coresemsurrender.c b/cpukit/score/src/coresemsurrender.c deleted file mode 100644 index 9b3d8fd4be..0000000000 --- a/cpukit/score/src/coresemsurrender.c +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * - * @brief Surrenders a Unit to a Semaphore - * - * @ingroup ScoreSemaphore - */ - -/* - * 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 - -CORE_semaphore_Status _CORE_semaphore_Surrender( - CORE_semaphore_Control *the_semaphore, - Objects_Id id, - CORE_semaphore_API_mp_support_callout api_semaphore_mp_support, - ISR_lock_Context *lock_context -) -{ - Thread_Control *the_thread; - CORE_semaphore_Status status; - - status = CORE_SEMAPHORE_STATUS_SUCCESSFUL; - - _Thread_queue_Acquire_critical( &the_semaphore->Wait_queue, lock_context ); - - the_thread = _Thread_queue_First_locked( &the_semaphore->Wait_queue ); - if ( the_thread != NULL ) { -#if defined(RTEMS_MULTIPROCESSING) - _Thread_Dispatch_disable(); -#endif - - _Thread_queue_Extract_critical( - &the_semaphore->Wait_queue, - the_thread, - lock_context - ); - -#if defined(RTEMS_MULTIPROCESSING) - if ( !_Objects_Is_local_id( the_thread->Object.id ) ) - (*api_semaphore_mp_support) ( the_thread, id ); - - _Thread_Dispatch_enable( _Per_CPU_Get() ); -#endif - } else { - if ( the_semaphore->count < the_semaphore->Attributes.maximum_count ) - the_semaphore->count += 1; - else - status = CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED; - - _Thread_queue_Release( &the_semaphore->Wait_queue, lock_context ); - } - - return status; -} -- cgit v1.2.3 From 4438ac2575fb9e0760bf53931a52d00dec4deb83 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sat, 2 May 2015 14:27:24 +0200 Subject: score: Fine grained locking for mutexes Update #2273. --- cpukit/libnetworking/rtems/rtems_glue.c | 19 ++---- cpukit/posix/src/mutexlocksupp.c | 7 -- cpukit/posix/src/mutexsetprioceiling.c | 11 ++- cpukit/posix/src/mutexunlock.c | 11 ++- cpukit/rtems/src/semobtain.c | 7 -- cpukit/rtems/src/semrelease.c | 6 +- cpukit/score/include/rtems/score/coremuteximpl.h | 40 ++++++----- cpukit/score/src/apimutexlock.c | 8 --- cpukit/score/src/apimutexunlock.c | 17 +++-- cpukit/score/src/coremutex.c | 5 +- cpukit/score/src/coremutexseize.c | 30 ++++++--- cpukit/score/src/coremutexsurrender.c | 86 +++++++++++++++++------- cpukit/score/src/debugisownerofallocator.c | 13 +--- 13 files changed, 143 insertions(+), 117 deletions(-) diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 63d4b8045f..e43dc6e1dc 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -378,9 +378,6 @@ rtems_bsdnet_semaphore_obtain (void) #ifdef RTEMS_FAST_MUTEX ISR_lock_Context lock_context; Thread_Control *executing; -#ifdef RTEMS_SMP - _Thread_Disable_dispatch(); -#endif _ISR_lock_ISR_disable(&lock_context); if (!the_networkSemaphore) rtems_panic ("rtems-net: network sema obtain: network not initialised\n"); @@ -393,9 +390,6 @@ rtems_bsdnet_semaphore_obtain (void) 0, /* forever */ &lock_context ); -#ifdef RTEMS_SMP - _Thread_Enable_dispatch(); -#endif if (executing->Wait.return_code) rtems_panic ("rtems-net: can't obtain network sema: %d\n", executing->Wait.return_code); @@ -416,18 +410,19 @@ void rtems_bsdnet_semaphore_release (void) { #ifdef RTEMS_FAST_MUTEX - int i; + ISR_lock_Context lock_context; + CORE_mutex_Status status; - _Thread_Disable_dispatch(); if (!the_networkSemaphore) rtems_panic ("rtems-net: network sema obtain: network not initialised\n"); - i = _CORE_mutex_Surrender ( + _ISR_lock_ISR_disable(&lock_context); + status = _CORE_mutex_Surrender ( &the_networkSemaphore->Core_control.mutex, networkSemaphore, - NULL + NULL, + &lock_context ); - _Thread_Enable_dispatch(); - if (i) + if (status != CORE_MUTEX_STATUS_SUCCESSFUL) rtems_panic ("rtems-net: can't release network sema: %i\n"); #else rtems_status_code sc; diff --git a/cpukit/posix/src/mutexlocksupp.c b/cpukit/posix/src/mutexlocksupp.c index 9b20f58d13..b63a89aa4e 100644 --- a/cpukit/posix/src/mutexlocksupp.c +++ b/cpukit/posix/src/mutexlocksupp.c @@ -54,9 +54,6 @@ int _POSIX_Mutex_Lock_support( switch ( location ) { case OBJECTS_LOCAL: -#if defined(RTEMS_SMP) - _Thread_Disable_dispatch(); -#endif executing = _Thread_Executing; _CORE_mutex_Seize( &the_mutex->Mutex, @@ -66,10 +63,6 @@ int _POSIX_Mutex_Lock_support( timeout, &lock_context ); -#if defined(RTEMS_SMP) - _Thread_Enable_dispatch(); -#endif - _Objects_Put_for_get_isr_disable( &the_mutex->Object ); return _POSIX_Mutex_Translate_core_mutex_return_code( (CORE_mutex_Status) executing->Wait.return_code ); diff --git a/cpukit/posix/src/mutexsetprioceiling.c b/cpukit/posix/src/mutexsetprioceiling.c index f0fb8f5ee6..32d92107cc 100644 --- a/cpukit/posix/src/mutexsetprioceiling.c +++ b/cpukit/posix/src/mutexsetprioceiling.c @@ -41,6 +41,7 @@ int pthread_mutex_setprioceiling( register POSIX_Mutex_Control *the_mutex; Objects_Locations location; Priority_Control the_priority; + ISR_lock_Context lock_context; if ( !old_ceiling ) return EINVAL; @@ -64,7 +65,11 @@ int pthread_mutex_setprioceiling( * NOTE: This makes it easier to get 100% binary coverage since the * bad Id case is handled by the switch. */ - the_mutex = _POSIX_Mutex_Get( mutex, &location ); + the_mutex = _POSIX_Mutex_Get_interrupt_disable( + mutex, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: @@ -78,9 +83,9 @@ int pthread_mutex_setprioceiling( _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, - NULL + NULL, + &lock_context ); - _Objects_Put( &the_mutex->Object ); return 0; diff --git a/cpukit/posix/src/mutexunlock.c b/cpukit/posix/src/mutexunlock.c index dbb9d1a3e6..c5b2375d1a 100644 --- a/cpukit/posix/src/mutexunlock.c +++ b/cpukit/posix/src/mutexunlock.c @@ -41,17 +41,22 @@ int pthread_mutex_unlock( register POSIX_Mutex_Control *the_mutex; Objects_Locations location; CORE_mutex_Status status; + ISR_lock_Context lock_context; - the_mutex = _POSIX_Mutex_Get( mutex, &location ); + the_mutex = _POSIX_Mutex_Get_interrupt_disable( + mutex, + &location, + &lock_context + ); switch ( location ) { case OBJECTS_LOCAL: status = _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, - NULL + NULL, + &lock_context ); - _Objects_Put( &the_mutex->Object ); return _POSIX_Mutex_Translate_core_mutex_return_code( status ); #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index 46d1b82f33..1ebc98bdb7 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -73,9 +73,6 @@ rtems_status_code rtems_semaphore_obtain( } else #endif if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { -#if defined(RTEMS_SMP) - _Thread_Disable_dispatch(); -#endif _CORE_mutex_Seize( &the_semaphore->Core_control.mutex, executing, @@ -84,10 +81,6 @@ rtems_status_code rtems_semaphore_obtain( timeout, &lock_context ); -#if defined(RTEMS_SMP) - _Thread_Enable_dispatch(); -#endif - _Objects_Put_for_get_isr_disable( &the_semaphore->Object ); return _Semaphore_Translate_core_mutex_return_code( executing->Wait.return_code ); } diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c index 1f0581eec1..7e4b98e7de 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -86,14 +86,12 @@ rtems_status_code rtems_semaphore_release( } else #endif if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { - _Thread_Disable_dispatch(); - _ISR_lock_ISR_enable( &lock_context ); mutex_status = _CORE_mutex_Surrender( &the_semaphore->Core_control.mutex, id, - MUTEX_MP_SUPPORT + MUTEX_MP_SUPPORT, + &lock_context ); - _Thread_Enable_dispatch(); return _Semaphore_Translate_core_mutex_return_code( mutex_status ); } else { semaphore_status = _CORE_semaphore_Surrender( diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index a6811680ff..54dadbe7e4 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -210,17 +210,10 @@ void _CORE_mutex_Seize_interrupt_blocking( * * @retval this method returns true if dispatch is in an unsafe state. */ -#ifdef RTEMS_SMP - #define _CORE_mutex_Check_dispatch_for_seize(_wait) \ - (_Thread_Dispatch_get_disable_level() != 1 \ - && (_wait) \ - && (_System_state_Get() >= SYSTEM_STATE_UP)) -#else - #define _CORE_mutex_Check_dispatch_for_seize(_wait) \ - (!_Thread_Dispatch_is_enabled() \ - && (_wait) \ - && (_System_state_Get() >= SYSTEM_STATE_UP)) -#endif +#define _CORE_mutex_Check_dispatch_for_seize(_wait) \ + (!_Thread_Dispatch_is_enabled() \ + && (_wait) \ + && (_System_state_Get() >= SYSTEM_STATE_UP)) /** * @brief Attempt to obtain the mutex. @@ -265,9 +258,10 @@ RTEMS_INLINE_ROUTINE void _CORE_mutex_Seize_body( INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE ); } + _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context ); if ( _CORE_mutex_Seize_interrupt_trylock( the_mutex, executing, lock_context ) ) { if ( !wait ) { - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); executing->Wait.return_code = CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT; } else { @@ -320,13 +314,15 @@ RTEMS_INLINE_ROUTINE void _CORE_mutex_Seize_body( * @param[in] id is the id of the RTEMS Object associated with this mutex * @param[in] api_mutex_mp_support is the routine that will be called when * unblocking a remote mutex + * @param[in] lock_context is the interrupt level * * @retval an indication of whether the routine succeeded or failed */ CORE_mutex_Status _CORE_mutex_Surrender( CORE_mutex_Control *the_mutex, Objects_Id id, - CORE_mutex_API_mp_support_callout api_mutex_mp_support + CORE_mutex_API_mp_support_callout api_mutex_mp_support, + ISR_lock_Context *lock_context ); /** @@ -472,7 +468,7 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body( } if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return 0; } /* else must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING * @@ -486,19 +482,21 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body( ceiling = the_mutex->Attributes.priority_ceiling; current = executing->current_priority; if ( current == ceiling ) { - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return 0; } if ( current > ceiling ) { - _Thread_Disable_dispatch(); - _ISR_lock_ISR_enable( lock_context ); + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable_critical(); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); _Thread_Change_priority( executing, ceiling, false ); - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); return 0; } /* if ( current < ceiling ) */ { @@ -506,7 +504,7 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body( the_mutex->holder = NULL; the_mutex->nest_count = 0; /* undo locking above */ executing->resource_count--; /* undo locking above */ - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return 0; } } @@ -522,12 +520,12 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body( switch ( the_mutex->Attributes.lock_nesting_behavior ) { case CORE_MUTEX_NESTING_ACQUIRES: the_mutex->nest_count++; - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return 0; #if defined(RTEMS_POSIX_API) case CORE_MUTEX_NESTING_IS_ERROR: executing->Wait.return_code = CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED; - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return 0; #endif case CORE_MUTEX_NESTING_BLOCKS: diff --git a/cpukit/score/src/apimutexlock.c b/cpukit/score/src/apimutexlock.c index 45ad0ba9e7..bcac71a9c3 100644 --- a/cpukit/score/src/apimutexlock.c +++ b/cpukit/score/src/apimutexlock.c @@ -30,10 +30,6 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex ) previous_thread_life_protection = _Thread_Set_life_protection( true ); - #if defined(RTEMS_SMP) - _Thread_Disable_dispatch(); - #endif - _ISR_lock_ISR_disable( &lock_context ); _CORE_mutex_Seize( @@ -49,8 +45,4 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex ) the_mutex->previous_thread_life_protection = previous_thread_life_protection; } - - #if defined(RTEMS_SMP) - _Thread_Enable_dispatch(); - #endif } diff --git a/cpukit/score/src/apimutexunlock.c b/cpukit/score/src/apimutexunlock.c index d0432a6f4a..04657ddcec 100644 --- a/cpukit/score/src/apimutexunlock.c +++ b/cpukit/score/src/apimutexunlock.c @@ -24,18 +24,21 @@ void _API_Mutex_Unlock( API_Mutex_Control *the_mutex ) { - bool previous_thread_life_protection; - bool restore_thread_life_protection; - - _Thread_Disable_dispatch(); + ISR_lock_Context lock_context; + bool previous_thread_life_protection; + bool restore_thread_life_protection; previous_thread_life_protection = the_mutex->previous_thread_life_protection; restore_thread_life_protection = the_mutex->Mutex.nest_count == 1; - _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, NULL ); - - _Thread_Enable_dispatch(); + _ISR_lock_ISR_disable( &lock_context ); + _CORE_mutex_Surrender( + &the_mutex->Mutex, + the_mutex->Object.id, + NULL, + &lock_context + ); if ( restore_thread_life_protection ) { _Thread_Set_life_protection( previous_thread_life_protection ); diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c index 2f584f2abf..58c6c42b06 100644 --- a/cpukit/score/src/coremutex.c +++ b/cpukit/score/src/coremutex.c @@ -48,13 +48,14 @@ CORE_mutex_Status _CORE_mutex_Initialize( if ( is_priority_ceiling || _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) { Priority_Control ceiling = the_mutex->Attributes.priority_ceiling; + Per_CPU_Control *cpu_self; /* * The mutex initialization is only protected by the allocator lock in * general. Disable thread dispatching before the priority check to * prevent interference with priority inheritance. */ - _Thread_Disable_dispatch(); + cpu_self = _Thread_Dispatch_disable(); if ( is_priority_ceiling && executing->current_priority < ceiling ) { _Thread_Enable_dispatch(); @@ -73,7 +74,7 @@ CORE_mutex_Status _CORE_mutex_Initialize( _Thread_Change_priority( executing, ceiling, false ); } - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); } } else { the_mutex->nest_count = 0; diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 4ecb702305..94c480d054 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -53,17 +53,28 @@ void _CORE_mutex_Seize_interrupt_blocking( ISR_lock_Context *lock_context ) { - _Thread_Disable_dispatch(); +#if !defined(RTEMS_SMP) + /* + * We must disable thread dispatching here since we enable the interrupts for + * priority inheritance mutexes. + */ + _Thread_Dispatch_disable(); +#endif if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) { Thread_Control *holder = the_mutex->holder; +#if !defined(RTEMS_SMP) /* - * To enable interrupts here works only since we own the Giant lock and - * only threads are allowed to seize and surrender mutexes with the - * priority inheritance protocol. + * To enable interrupts here works only since exactly one executing thread + * exists and only threads are allowed to seize and surrender mutexes with + * the priority inheritance protocol. On SMP configurations more than one + * executing thread may exist, so here we must not release the lock, since + * otherwise the current holder may be no longer the holder of the mutex + * once we released the lock. */ - _ISR_lock_ISR_enable( lock_context ); + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); +#endif _Scheduler_Change_priority_if_higher( _Scheduler_Get( holder ), @@ -72,10 +83,11 @@ void _CORE_mutex_Seize_interrupt_blocking( false ); - _ISR_lock_ISR_disable( lock_context ); +#if !defined(RTEMS_SMP) + _Thread_queue_Acquire( &the_mutex->Wait_queue, lock_context ); +#endif } - _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context ); _Thread_queue_Enqueue_critical( &the_mutex->Wait_queue, executing, @@ -85,6 +97,8 @@ void _CORE_mutex_Seize_interrupt_blocking( lock_context ); - _Thread_Enable_dispatch(); +#if !defined(RTEMS_SMP) + _Thread_Dispatch_enable( _Per_CPU_Get() ); +#endif } diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c index 8fba301de9..3f0cd8619c 100644 --- a/cpukit/score/src/coremutexsurrender.c +++ b/cpukit/score/src/coremutexsurrender.c @@ -89,11 +89,12 @@ CORE_mutex_Status _CORE_mutex_Surrender( CORE_mutex_Control *the_mutex, #if defined(RTEMS_MULTIPROCESSING) Objects_Id id, - CORE_mutex_API_mp_support_callout api_mutex_mp_support + CORE_mutex_API_mp_support_callout api_mutex_mp_support, #else Objects_Id id __attribute__((unused)), - CORE_mutex_API_mp_support_callout api_mutex_mp_support __attribute__((unused)) + CORE_mutex_API_mp_support_callout api_mutex_mp_support __attribute__((unused)), #endif + ISR_lock_Context *lock_context ) { Thread_Control *the_thread; @@ -110,14 +111,20 @@ CORE_mutex_Status _CORE_mutex_Surrender( */ if ( the_mutex->Attributes.only_owner_release ) { - if ( !_Thread_Is_executing( holder ) ) + if ( !_Thread_Is_executing( holder ) ) { + _ISR_lock_ISR_enable( lock_context ); return CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE; + } } + _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context ); + /* XXX already unlocked -- not right status */ - if ( !the_mutex->nest_count ) + if ( !the_mutex->nest_count ) { + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return CORE_MUTEX_STATUS_SUCCESSFUL; + } the_mutex->nest_count--; @@ -130,10 +137,12 @@ CORE_mutex_Status _CORE_mutex_Surrender( #if defined(RTEMS_DEBUG) switch ( the_mutex->Attributes.lock_nesting_behavior ) { case CORE_MUTEX_NESTING_ACQUIRES: + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return CORE_MUTEX_STATUS_SUCCESSFUL; #if defined(RTEMS_POSIX_API) case CORE_MUTEX_NESTING_IS_ERROR: /* should never occur */ + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED; #endif case CORE_MUTEX_NESTING_BLOCKS: @@ -141,6 +150,7 @@ CORE_mutex_Status _CORE_mutex_Surrender( break; } #else + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */ return CORE_MUTEX_STATUS_SUCCESSFUL; #endif @@ -155,20 +165,12 @@ CORE_mutex_Status _CORE_mutex_Surrender( CORE_mutex_Status pop_status = _CORE_mutex_Pop_priority( the_mutex, holder ); - if ( pop_status != CORE_MUTEX_STATUS_SUCCESSFUL ) + if ( pop_status != CORE_MUTEX_STATUS_SUCCESSFUL ) { + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); return pop_status; + } holder->resource_count--; - - /* - * Whether or not someone is waiting for the mutex, an - * inherited priority must be lowered if this is the last - * mutex (i.e. resource) this task has. - */ - if ( !_Thread_Owns_resources( holder ) && - holder->real_priority != holder->current_priority ) { - _Thread_Change_priority( holder, holder->real_priority, true ); - } } the_mutex->holder = NULL; @@ -176,20 +178,21 @@ CORE_mutex_Status _CORE_mutex_Surrender( * Now we check if another thread was waiting for this mutex. If so, * transfer the mutex to that thread. */ - if ( ( the_thread = _Thread_queue_Dequeue( &the_mutex->Wait_queue ) ) ) { + if ( ( the_thread = _Thread_queue_First_locked( &the_mutex->Wait_queue ) ) ) { + /* + * We must extract the thread now since this will restore its default + * thread lock. This is necessary to avoid a deadlock in the + * _Thread_Change_priority() below due to a recursive thread queue lock + * acquire. + */ + _Thread_queue_Extract_locked( &the_mutex->Wait_queue, the_thread ); #if defined(RTEMS_MULTIPROCESSING) - if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { - - the_mutex->holder = NULL; - the_mutex->nest_count = 1; + _Thread_Dispatch_disable(); - ( *api_mutex_mp_support)( the_thread, id ); - - } else + if ( _Objects_Is_local_id( the_thread->Object.id ) ) #endif { - the_mutex->holder = the_thread; the_mutex->nest_count = 1; @@ -215,6 +218,41 @@ CORE_mutex_Status _CORE_mutex_Surrender( break; } } + + _Thread_queue_Unblock_critical( + &the_mutex->Wait_queue, + the_thread, + lock_context + ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + + the_mutex->holder = NULL; + the_mutex->nest_count = 1; + + ( *api_mutex_mp_support)( the_thread, id ); + + } + + _Thread_Dispatch_enable( _Per_CPU_Get() ); +#endif + } else { + _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); + } + + /* + * Whether or not someone is waiting for the mutex, an + * inherited priority must be lowered if this is the last + * mutex (i.e. resource) this task has. + */ + if ( !_Thread_Owns_resources( holder ) && + holder->real_priority != holder->current_priority ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + _Thread_Change_priority( holder, holder->real_priority, true ); + _Thread_Dispatch_enable( cpu_self ); } return CORE_MUTEX_STATUS_SUCCESSFUL; diff --git a/cpukit/score/src/debugisownerofallocator.c b/cpukit/score/src/debugisownerofallocator.c index 7879902025..57da2ca001 100644 --- a/cpukit/score/src/debugisownerofallocator.c +++ b/cpukit/score/src/debugisownerofallocator.c @@ -18,8 +18,7 @@ #include #include -#include -#include +#include #if defined( RTEMS_DEBUG ) bool _Debug_Is_owner_of_allocator( void ) @@ -27,20 +26,12 @@ API_Mutex_Control *mutex = _RTEMS_Allocator_Mutex; bool owner; - /* - * We have to synchronize with the _CORE_mutex_Surrender() operation, - * otherwise we may observe an outdated mutex holder. - */ - _Thread_Disable_dispatch(); - if ( mutex != NULL ) { - owner = mutex->Mutex.holder == _Thread_Executing; + owner = mutex->Mutex.holder == _Thread_Get_executing(); } else { owner = false; } - _Thread_Enable_dispatch(); - return owner; } #endif -- cgit v1.2.3 From 900d337f960cb7cc53f5c93c29a503e5ced2c31f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 5 May 2015 13:05:54 +0200 Subject: score: Rework _Thread_Change_priority() Move the writes to Thread_Control::current_priority and Thread_Control::real_priority into _Thread_Change_priority() under the protection of the thread lock. Add a filter function to _Thread_Change_priority() to enable specialized variants. Avoid race conditions during a thread priority restore with the new Thread_Control::priority_restore_hint for an important average case optimizations used by priority inheritance mutexes. Update #2273. --- cpukit/posix/src/pthread.c | 96 ++++++++++--------- cpukit/posix/src/pthreadsetschedparam.c | 13 ++- cpukit/rtems/src/tasksetpriority.c | 20 ++-- cpukit/score/include/rtems/score/coremuteximpl.h | 6 +- cpukit/score/include/rtems/score/mrspimpl.h | 36 +++---- cpukit/score/include/rtems/score/schedulerimpl.h | 48 ---------- cpukit/score/include/rtems/score/thread.h | 54 ++++++++++- cpukit/score/include/rtems/score/threadimpl.h | 114 ++++++++++++++++++++--- cpukit/score/src/coremutex.c | 19 ++-- cpukit/score/src/coremutexseize.c | 8 +- cpukit/score/src/coremutexsurrender.c | 31 +++--- cpukit/score/src/schedulercbs.c | 6 +- cpukit/score/src/schedulercbsreleasejob.c | 4 +- cpukit/score/src/scheduleredfreleasejob.c | 4 +- cpukit/score/src/thread.c | 1 + cpukit/score/src/threadchangepriority.c | 71 +++++++++++++- cpukit/score/src/threadinitialize.c | 3 +- cpukit/score/src/threadrestart.c | 46 ++++++--- cpukit/score/src/threadsetpriority.c | 37 +++++++- testsuites/smptests/smpscheduler03/init.c | 62 ++++++++---- 20 files changed, 452 insertions(+), 227 deletions(-) diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index a3a73f117a..6395ec0ebd 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -83,6 +83,23 @@ pthread_attr_t _POSIX_Threads_Default_attributes = { #endif }; +static bool _POSIX_Threads_Sporadic_budget_TSR_filter( + Thread_Control *the_thread, + Priority_Control *new_priority, + void *arg +) +{ + the_thread->real_priority = *new_priority; + + /* + * If holding a resource, then do not change it. + * + * If this would make them less important, then do not change it. + */ + return !_Thread_Owns_resources( the_thread ) && + _Thread_Priority_less_than( the_thread->current_priority, *new_priority ); +} + /* * _POSIX_Threads_Sporadic_budget_TSR */ @@ -92,7 +109,6 @@ void _POSIX_Threads_Sporadic_budget_TSR( ) { uint32_t ticks; - uint32_t new_priority; Thread_Control *the_thread; POSIX_API_Control *api; @@ -105,27 +121,13 @@ void _POSIX_Threads_Sporadic_budget_TSR( the_thread->cpu_time_budget = ticks; - new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority ); - the_thread->real_priority = new_priority; - - /* - * If holding a resource, then do not change it. - */ - #if 0 - printk( "TSR %d %d %d\n", the_thread->resource_count, - the_thread->current_priority, new_priority ); - #endif - if ( !_Thread_Owns_resources( the_thread ) ) { - /* - * If this would make them less important, then do not change it. - */ - if ( the_thread->current_priority > new_priority ) { - _Thread_Change_priority( the_thread, new_priority, true ); - #if 0 - printk( "raise priority\n" ); - #endif - } - } + _Thread_Change_priority( + the_thread, + _POSIX_Priority_To_core( api->schedparam.sched_priority ), + NULL, + _POSIX_Threads_Sporadic_budget_TSR_filter, + true + ); /* ticks is guaranteed to be at least one */ ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period ); @@ -133,6 +135,25 @@ void _POSIX_Threads_Sporadic_budget_TSR( _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks ); } +static bool _POSIX_Threads_Sporadic_budget_callout_filter( + Thread_Control *the_thread, + Priority_Control *new_priority, + void *arg +) +{ + the_thread->real_priority = *new_priority; + + /* + * If holding a resource, then do not change it. + * + * Make sure we are actually lowering it. If they have lowered it + * to logically lower than sched_ss_low_priority, then we do not want to + * change it. + */ + return !_Thread_Owns_resources( the_thread ) && + _Thread_Priority_less_than( *new_priority, the_thread->current_priority ); +} + /* * _POSIX_Threads_Sporadic_budget_callout */ @@ -141,7 +162,6 @@ void _POSIX_Threads_Sporadic_budget_callout( ) { POSIX_API_Control *api; - uint32_t new_priority; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; @@ -151,29 +171,13 @@ void _POSIX_Threads_Sporadic_budget_callout( */ the_thread->cpu_time_budget = UINT32_MAX; - new_priority = _POSIX_Priority_To_core(api->schedparam.sched_ss_low_priority); - the_thread->real_priority = new_priority; - - /* - * If holding a resource, then do not change it. - */ - #if 0 - printk( "callout %d %d %d\n", the_thread->resource_count, - the_thread->current_priority, new_priority ); - #endif - if ( !_Thread_Owns_resources( the_thread ) ) { - /* - * Make sure we are actually lowering it. If they have lowered it - * to logically lower than sched_ss_low_priority, then we do not want to - * change it. - */ - if ( the_thread->current_priority < new_priority ) { - _Thread_Change_priority( the_thread, new_priority, true ); - #if 0 - printk( "lower priority\n" ); - #endif - } - } + _Thread_Change_priority( + the_thread, + _POSIX_Priority_To_core( api->schedparam.sched_ss_low_priority ), + NULL, + _POSIX_Threads_Sporadic_budget_callout_filter, + true + ); } /* diff --git a/cpukit/posix/src/pthreadsetschedparam.c b/cpukit/posix/src/pthreadsetschedparam.c index dcb70bdec8..067e6ba509 100644 --- a/cpukit/posix/src/pthreadsetschedparam.c +++ b/cpukit/posix/src/pthreadsetschedparam.c @@ -44,6 +44,7 @@ int pthread_setschedparam( Thread_CPU_budget_algorithm_callout budget_callout; Objects_Locations location; int rc; + Priority_Control unused; /* * Check all the parameters @@ -87,13 +88,11 @@ int pthread_setschedparam( the_thread->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice(); - the_thread->real_priority = - _POSIX_Priority_To_core( api->schedparam.sched_priority ); - - _Thread_Change_priority( - the_thread, - the_thread->real_priority, - true + _Thread_Set_priority( + the_thread, + _POSIX_Priority_To_core( api->schedparam.sched_priority ), + &unused, + true ); break; diff --git a/cpukit/rtems/src/tasksetpriority.c b/cpukit/rtems/src/tasksetpriority.c index 4e4835675d..582c67f9f2 100644 --- a/cpukit/rtems/src/tasksetpriority.c +++ b/cpukit/rtems/src/tasksetpriority.c @@ -41,16 +41,18 @@ rtems_status_code rtems_task_set_priority( switch ( location ) { case OBJECTS_LOCAL: - *old_priority = _RTEMS_tasks_Priority_from_Core( - the_thread->current_priority - ); if ( new_priority != RTEMS_CURRENT_PRIORITY ) { - the_thread->real_priority = _RTEMS_tasks_Priority_to_Core( - new_priority - ); - if ( !_Thread_Owns_resources( the_thread ) || - the_thread->current_priority > new_priority ) - _Thread_Change_priority( the_thread, new_priority, false ); + _Thread_Set_priority( + the_thread, + _RTEMS_tasks_Priority_to_Core( new_priority ), + old_priority, + false + ); + *old_priority = _RTEMS_tasks_Priority_from_Core( *old_priority ); + } else { + *old_priority = _RTEMS_tasks_Priority_from_Core( + the_thread->current_priority + ); } _Objects_Put( &the_thread->Object ); return RTEMS_SUCCESSFUL; diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index 54dadbe7e4..ca9d61df4a 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -491,11 +491,7 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body( cpu_self = _Thread_Dispatch_disable_critical(); _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); - _Thread_Change_priority( - executing, - ceiling, - false - ); + _Thread_Raise_priority( executing, ceiling ); _Thread_Dispatch_enable( cpu_self ); return 0; } diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h index 07f78ce7e9..05aee42a22 100644 --- a/cpukit/score/include/rtems/score/mrspimpl.h +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -36,13 +36,18 @@ extern "C" { * @{ */ -RTEMS_INLINE_ROUTINE void _MRSP_Elevate_priority( - MRSP_Control *mrsp, - Thread_Control *new_owner, - Priority_Control ceiling_priority +RTEMS_INLINE_ROUTINE bool _MRSP_Restore_priority_filter( + Thread_Control *thread, + Priority_Control *new_priority, + void *arg ) { - _Thread_Change_priority( new_owner, ceiling_priority, false ); + *new_priority = _Thread_Priority_highest( + thread->real_priority, + *new_priority + ); + + return *new_priority != thread->current_priority; } RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority( @@ -55,13 +60,13 @@ RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority( * or priority inheritance semaphores. */ if ( thread->resource_count == 0 ) { - Priority_Control new_priority = _Scheduler_Highest_priority_of_two( - _Scheduler_Get( thread ), + _Thread_Change_priority( + thread, initial_priority, - thread->real_priority + NULL, + _MRSP_Restore_priority_filter, + true ); - - _Thread_Change_priority( thread, new_priority, true ); } } @@ -75,7 +80,7 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership( _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource ); _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node ); mrsp->initial_priority_of_owner = initial_priority; - _MRSP_Elevate_priority( mrsp, new_owner, ceiling_priority ); + _Thread_Raise_priority( new_owner, ceiling_priority ); _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER ); } @@ -177,7 +182,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL ); rival.status = MRSP_WAIT_FOR_OWNERSHIP; - _MRSP_Elevate_priority( mrsp, executing, ceiling_priority ); + _Thread_Raise_priority( executing, ceiling_priority ); _ISR_Disable( level ); @@ -235,10 +240,9 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain( Priority_Control initial_priority = executing->current_priority; Priority_Control ceiling_priority = _MRSP_Get_ceiling_priority( mrsp, scheduler_index ); - bool priority_ok = !_Scheduler_Is_priority_higher_than( - scheduler, - initial_priority, - ceiling_priority + bool priority_ok = !_Thread_Priority_less_than( + ceiling_priority, + initial_priority ); Resource_Node *owner; diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h index 212bace075..cadebfd02f 100644 --- a/cpukit/score/include/rtems/score/schedulerimpl.h +++ b/cpukit/score/include/rtems/score/schedulerimpl.h @@ -693,54 +693,6 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_higher_than( return _Scheduler_Priority_compare( scheduler, p1, p2 ) > 0; } -/** - * @brief Returns the priority encoding @a p1 or @a p2 with the higher priority - * in the intuitive sense of priority. - */ -RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Highest_priority_of_two( - const Scheduler_Control *scheduler, - Priority_Control p1, - Priority_Control p2 -) -{ - return _Scheduler_Is_priority_higher_than( scheduler, p1, p2 ) ? p1 : p2; -} - -/** - * @brief Sets the thread priority to @a priority if it is higher than the - * current priority of the thread in the intuitive sense of priority. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Set_priority_if_higher( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - Priority_Control priority -) -{ - Priority_Control current = the_thread->current_priority; - - if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) { - _Thread_Set_priority( the_thread, priority ); - } -} - -/** - * @brief Changes the thread priority to @a priority if it is higher than the - * current priority of the thread in the intuitive sense of priority. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - Priority_Control priority, - bool prepend_it -) -{ - Priority_Control current = the_thread->current_priority; - - if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) { - _Thread_Change_priority( the_thread, priority, prepend_it ); - } -} - RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count( const Scheduler_Control *scheduler ) diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index b6662e49af..39fcb1707f 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -366,9 +366,21 @@ typedef struct { Objects_Control Object; /** This field is the current execution state of this proxy. */ States_Control current_state; - /** This field is the current priority state of this proxy. */ + + /** + * @brief This field is the current priority state of this thread. + * + * Writes to this field are only allowed in _Thread_Initialize() or via + * _Thread_Change_priority(). + */ Priority_Control current_priority; - /** This field is the base priority of this proxy. */ + + /** + * @brief This field is the base priority of this thread. + * + * Writes to this field are only allowed in _Thread_Initialize() or via + * _Thread_Change_priority(). + */ Priority_Control real_priority; /** @@ -379,6 +391,17 @@ typedef struct { */ uint32_t priority_generation; + /** + * @brief Hints if a priority restore is necessary once the resource count + * changes from one to zero. + * + * This is an optimization to speed up the mutex surrender sequence in case + * no attempt to change the priority was made during the mutex ownership. On + * SMP configurations atomic fences must synchronize writes to + * Thread_Control::priority_restore_hint and Thread_Control::resource_count. + */ + bool priority_restore_hint; + /** This field is the number of mutexes currently held by this proxy. */ uint32_t resource_count; @@ -653,9 +676,21 @@ struct Thread_Control_struct { Objects_Control Object; /** This field is the current execution state of this thread. */ States_Control current_state; - /** This field is the current priority state of this thread. */ + + /** + * @brief This field is the current priority state of this thread. + * + * Writes to this field are only allowed in _Thread_Initialize() or via + * _Thread_Change_priority(). + */ Priority_Control current_priority; - /** This field is the base priority of this thread. */ + + /** + * @brief This field is the base priority of this thread. + * + * Writes to this field are only allowed in _Thread_Initialize() or via + * _Thread_Change_priority(). + */ Priority_Control real_priority; /** @@ -666,6 +701,17 @@ struct Thread_Control_struct { */ uint32_t priority_generation; + /** + * @brief Hints if a priority restore is necessary once the resource count + * changes from one to zero. + * + * This is an optimization to speed up the mutex surrender sequence in case + * no attempt to change the priority was made during the mutex ownership. On + * SMP configurations atomic fences must synchronize writes to + * Thread_Control::priority_restore_hint and Thread_Control::resource_count. + */ + bool priority_restore_hint; + /** This field is the number of mutexes currently held by this thread. */ uint32_t resource_count; /** This field is the blocking information for this thread. */ diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index b8c235c846..ffff220288 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -333,33 +333,119 @@ void _Thread_Delay_ended( ); /** - * @brief Change the priority of a thread. + * @brief Returns true if the left thread priority is less than the right + * thread priority in the intuitive sense of priority and false otherwise. + */ +RTEMS_INLINE_ROUTINE bool _Thread_Priority_less_than( + Priority_Control left, + Priority_Control right +) +{ + return left > right; +} + +/** + * @brief Returns the highest priority of the left and right thread priorities + * in the intuitive sense of priority. + */ +RTEMS_INLINE_ROUTINE Priority_Control _Thread_Priority_highest( + Priority_Control left, + Priority_Control right +) +{ + return _Thread_Priority_less_than( left, right ) ? right : left; +} + +/** + * @brief Filters a thread priority change. + * + * Called by _Thread_Change_priority() under the protection of the thread lock. * - * This routine changes the current priority of @a the_thread to - * @a new_priority. It performs any necessary scheduling operations - * including the selection of a new heir thread. + * @param[in] the_thread The thread. + * @param[in, out] new_priority The new priority of the thread. The filter may + * alter this value. + * @param[in] arg The argument passed to _Thread_Change_priority(). * - * @param[in] the_thread is the thread to change - * @param[in] new_priority is the priority to set @a the_thread to - * @param[in] prepend_it is a switch to prepend the thread + * @retval true Change the current priority. + * @retval false Otherwise. */ -void _Thread_Change_priority ( +typedef bool ( *Thread_Change_priority_filter )( Thread_Control *the_thread, - Priority_Control new_priority, - bool prepend_it + Priority_Control *new_priority, + void *arg +); + +/** + * @brief Changes the priority of a thread if allowed by the filter function. + * + * It changes current priority of the thread to the new priority in case the + * filter function returns true. In this case the scheduler is notified of the + * priority change as well. + * + * @param[in] the_thread The thread. + * @param[in] new_priority The new priority of the thread. + * @param[in] arg The argument for the filter function. + * @param[in] filter The filter function to determine if a priority change is + * allowed and optionally perform other actions under the protection of the + * thread lock simultaneously with the update of the current priority. + * @param[in] prepend_it In case this is true, then the thread is prepended to + * its priority group in its scheduler instance, otherwise it is appended. + */ +void _Thread_Change_priority( + Thread_Control *the_thread, + Priority_Control new_priority, + void *arg, + Thread_Change_priority_filter filter, + bool prepend_it ); /** - * @brief Set thread priority. + * @brief Raises the priority of a thread. + * + * It changes the current priority of the thread to the new priority if the new + * priority is higher than the current priority. In this case the thread is + * appended to its new priority group in its scheduler instance. * - * This routine updates the priority related fields in the_thread - * control block to indicate the current priority is now new_priority. + * @param[in] the_thread The thread. + * @param[in] new_priority The new priority of the thread. + * + * @see _Thread_Change_priority(). */ -void _Thread_Set_priority( +void _Thread_Raise_priority( Thread_Control *the_thread, Priority_Control new_priority ); +/** + * @brief Sets the current to the real priority of a thread. + * + * Sets the priority restore hint to false. + */ +void _Thread_Restore_priority( Thread_Control *the_thread ); + +/** + * @brief Sets the priority of a thread. + * + * It sets the real priority of the thread. In addition it changes the current + * priority of the thread if the new priority is higher than the current + * priority or the thread owns no resources. + * + * @param[in] the_thread The thread. + * @param[in] new_priority The new priority of the thread. + * @param[out] old_priority The old real priority of the thread. This pointer + * must not be @c NULL. + * @param[in] prepend_it In case this is true, then the thread is prepended to + * its priority group in its scheduler instance, otherwise it is appended. + * + * @see _Thread_Change_priority(). + */ +void _Thread_Set_priority( + Thread_Control *the_thread, + Priority_Control new_priority, + Priority_Control *old_priority, + bool prepend_it +); + /** * @brief Maps thread Id to a TCB pointer. * diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c index 58c6c42b06..6bb535a8ec 100644 --- a/cpukit/score/src/coremutex.c +++ b/cpukit/score/src/coremutex.c @@ -50,15 +50,20 @@ CORE_mutex_Status _CORE_mutex_Initialize( Priority_Control ceiling = the_mutex->Attributes.priority_ceiling; Per_CPU_Control *cpu_self; - /* - * The mutex initialization is only protected by the allocator lock in - * general. Disable thread dispatching before the priority check to - * prevent interference with priority inheritance. - */ + /* The mutex initialization is only protected by the allocator lock */ cpu_self = _Thread_Dispatch_disable(); + /* + * The test to check for a ceiling violation is a bit arbitrary. In case + * this thread is the owner of a priority inheritance mutex, then it may + * get a higher priority later or anytime on SMP configurations. + */ if ( is_priority_ceiling && executing->current_priority < ceiling ) { - _Thread_Enable_dispatch(); + /* + * There is no need to undo the previous work since this error aborts + * the object creation. + */ + _Thread_Dispatch_enable( cpu_self ); return CORE_MUTEX_STATUS_CEILING_VIOLATED; } @@ -71,7 +76,7 @@ CORE_mutex_Status _CORE_mutex_Initialize( executing->resource_count++; if ( is_priority_ceiling ) { - _Thread_Change_priority( executing, ceiling, false ); + _Thread_Raise_priority( executing, ceiling ); } _Thread_Dispatch_enable( cpu_self ); diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 94c480d054..d5f85c5fad 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -76,12 +75,7 @@ void _CORE_mutex_Seize_interrupt_blocking( _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); #endif - _Scheduler_Change_priority_if_higher( - _Scheduler_Get( holder ), - holder, - executing->current_priority, - false - ); + _Thread_Raise_priority( holder, executing->current_priority ); #if !defined(RTEMS_SMP) _Thread_queue_Acquire( &the_mutex->Wait_queue, lock_context ); diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c index 3f0cd8619c..d5dde1e8e6 100644 --- a/cpukit/score/src/coremutexsurrender.c +++ b/cpukit/score/src/coremutexsurrender.c @@ -207,14 +207,10 @@ CORE_mutex_Status _CORE_mutex_Surrender( case CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING: _CORE_mutex_Push_priority( the_mutex, the_thread ); the_thread->resource_count++; - if (the_mutex->Attributes.priority_ceiling < - the_thread->current_priority){ - _Thread_Change_priority( - the_thread, - the_mutex->Attributes.priority_ceiling, - false - ); - } + _Thread_Raise_priority( + the_thread, + the_mutex->Attributes.priority_ceiling + ); break; } } @@ -246,13 +242,20 @@ CORE_mutex_Status _CORE_mutex_Surrender( * inherited priority must be lowered if this is the last * mutex (i.e. resource) this task has. */ - if ( !_Thread_Owns_resources( holder ) && - holder->real_priority != holder->current_priority ) { - Per_CPU_Control *cpu_self; + if ( !_Thread_Owns_resources( holder ) ) { + /* + * Ensure that the holder resource count is visible to all other processors + * and that we read the latest priority restore hint. + */ + _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); - cpu_self = _Thread_Dispatch_disable(); - _Thread_Change_priority( holder, holder->real_priority, true ); - _Thread_Dispatch_enable( cpu_self ); + if ( holder->priority_restore_hint ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + _Thread_Restore_priority( holder ); + _Thread_Dispatch_enable( cpu_self ); + } } return CORE_MUTEX_STATUS_SUCCESSFUL; diff --git a/cpukit/score/src/schedulercbs.c b/cpukit/score/src/schedulercbs.c index 44221cdbdf..98ec0eb29e 100644 --- a/cpukit/score/src/schedulercbs.c +++ b/cpukit/score/src/schedulercbs.c @@ -27,15 +27,13 @@ void _Scheduler_CBS_Budget_callout( ) { Priority_Control new_priority; + Priority_Control unused; Scheduler_CBS_Node *node; Scheduler_CBS_Server_id server_id; /* Put violating task to background until the end of period. */ new_priority = the_thread->Start.initial_priority; - if ( the_thread->real_priority != new_priority ) - the_thread->real_priority = new_priority; - if ( the_thread->current_priority != new_priority ) - _Thread_Change_priority(the_thread, new_priority, true); + _Thread_Set_priority( the_thread, new_priority, &unused, true ); /* Invoke callback function if any. */ node = _Scheduler_CBS_Thread_get_node( the_thread ); diff --git a/cpukit/score/src/schedulercbsreleasejob.c b/cpukit/score/src/schedulercbsreleasejob.c index 36a31551cf..a9f8e33201 100644 --- a/cpukit/score/src/schedulercbsreleasejob.c +++ b/cpukit/score/src/schedulercbsreleasejob.c @@ -32,6 +32,7 @@ void _Scheduler_CBS_Release_job( Scheduler_CBS_Node *node = _Scheduler_CBS_Thread_get_node( the_thread ); Scheduler_CBS_Server *serv_info = node->cbs_server; Priority_Control new_priority; + Priority_Control unused; if (deadline) { /* Initializing or shifting deadline. */ @@ -51,6 +52,5 @@ void _Scheduler_CBS_Release_job( if (serv_info) the_thread->cpu_time_budget = serv_info->parameters.budget; - the_thread->real_priority = new_priority; - _Thread_Change_priority(the_thread, new_priority, true); + _Thread_Set_priority( the_thread, new_priority, &unused, true ); } diff --git a/cpukit/score/src/scheduleredfreleasejob.c b/cpukit/score/src/scheduleredfreleasejob.c index 6c1b642890..2c3db65b64 100644 --- a/cpukit/score/src/scheduleredfreleasejob.c +++ b/cpukit/score/src/scheduleredfreleasejob.c @@ -29,6 +29,7 @@ void _Scheduler_EDF_Release_job( ) { Priority_Control new_priority; + Priority_Control unused; (void) scheduler; @@ -42,6 +43,5 @@ void _Scheduler_EDF_Release_job( new_priority = the_thread->Start.initial_priority; } - the_thread->real_priority = new_priority; - _Thread_Change_priority(the_thread, new_priority, true); + _Thread_Set_priority( the_thread, new_priority, &unused, true ); } diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c index 8a34ced684..ef9788ca41 100644 --- a/cpukit/score/src/thread.c +++ b/cpukit/score/src/thread.c @@ -32,6 +32,7 @@ THREAD_OFFSET_ASSERT( current_state ); THREAD_OFFSET_ASSERT( current_priority ); THREAD_OFFSET_ASSERT( real_priority ); THREAD_OFFSET_ASSERT( priority_generation ); +THREAD_OFFSET_ASSERT( priority_restore_hint ); THREAD_OFFSET_ASSERT( resource_count ); THREAD_OFFSET_ASSERT( Wait ); THREAD_OFFSET_ASSERT( Timer ); diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c index 3223544fe3..8f5d14f412 100644 --- a/cpukit/score/src/threadchangepriority.c +++ b/cpukit/score/src/threadchangepriority.c @@ -21,12 +21,13 @@ #include #include -#include void _Thread_Change_priority( - Thread_Control *the_thread, - Priority_Control new_priority, - bool prepend_it + Thread_Control *the_thread, + Priority_Control new_priority, + void *arg, + Thread_Change_priority_filter filter, + bool prepend_it ) { ISR_lock_Context lock_context; @@ -34,11 +35,21 @@ void _Thread_Change_priority( lock = _Thread_Lock_acquire( the_thread, &lock_context ); + /* + * For simplicity set the priority restore hint unconditionally since this is + * an average case optimization. Otherwise complicated atomic operations + * would be necessary. Synchronize with a potential read of the resource + * count in the filter function. See also _CORE_mutex_Surrender(), + * _Thread_Set_priority_filter() and _Thread_Restore_priority_filter(). + */ + the_thread->priority_restore_hint = true; + _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); + /* * Do not bother recomputing all the priority related information if * we are not REALLY changing priority. */ - if ( the_thread->current_priority != new_priority ) { + if ( ( *filter )( the_thread, &new_priority, arg ) ) { uint32_t my_generation; my_generation = the_thread->priority_generation + 1; @@ -72,3 +83,53 @@ void _Thread_Change_priority( _Thread_Lock_release( lock, &lock_context ); } } + +static bool _Thread_Raise_priority_filter( + Thread_Control *the_thread, + Priority_Control *new_priority, + void *arg +) +{ + return _Thread_Priority_less_than( + the_thread->current_priority, + *new_priority + ); +} + +void _Thread_Raise_priority( + Thread_Control *the_thread, + Priority_Control new_priority +) +{ + _Thread_Change_priority( + the_thread, + new_priority, + NULL, + _Thread_Raise_priority_filter, + false + ); +} + +static bool _Thread_Restore_priority_filter( + Thread_Control *the_thread, + Priority_Control *new_priority, + void *arg +) +{ + *new_priority = the_thread->real_priority; + + the_thread->priority_restore_hint = false; + + return *new_priority != the_thread->current_priority; +} + +void _Thread_Restore_priority( Thread_Control *the_thread ) +{ + _Thread_Change_priority( + the_thread, + 0, + NULL, + _Thread_Restore_priority_filter, + true + ); +} diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 9f5df257aa..2133d7485b 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -201,6 +201,7 @@ bool _Thread_Initialize( the_thread->Wait.queue = NULL; the_thread->Wait.operations = &_Thread_queue_Operations_default; the_thread->resource_count = 0; + the_thread->current_priority = priority; the_thread->real_priority = priority; the_thread->priority_generation = 0; the_thread->Start.initial_priority = priority; @@ -210,7 +211,7 @@ bool _Thread_Initialize( _Scheduler_Node_initialize( scheduler, the_thread ); scheduler_node_initialized = true; - _Thread_Set_priority( the_thread, priority ); + _Scheduler_Update_priority( the_thread, priority ); /* * Initialize the CPU usage statistics diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 8dea518e10..b98b6388f8 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -42,6 +42,28 @@ static Thread_Zombie_control _Thread_Zombies = { .Lock = ISR_LOCK_INITIALIZER( "thread zombies" ) }; +static bool _Thread_Raise_real_priority_filter( + Thread_Control *the_thread, + Priority_Control *new_priority_ptr, + void *arg +) +{ + Priority_Control real_priority; + Priority_Control new_priority; + Priority_Control current_priority; + + real_priority = the_thread->real_priority; + new_priority = *new_priority_ptr; + current_priority = the_thread->current_priority; + + new_priority = _Thread_Priority_highest( real_priority, new_priority ); + *new_priority_ptr = new_priority; + + the_thread->real_priority = new_priority; + + return _Thread_Priority_less_than( current_priority, new_priority ); +} + static void _Thread_Make_zombie( Thread_Control *the_thread ) { ISR_lock_Context lock_context; @@ -231,12 +253,17 @@ static void _Thread_Start_life_change( the_thread->is_preemptible = the_thread->Start.is_preemptible; the_thread->budget_algorithm = the_thread->Start.budget_algorithm; the_thread->budget_callout = the_thread->Start.budget_callout; - the_thread->real_priority = priority; _Thread_Set_state( the_thread, STATES_RESTARTING ); _Thread_queue_Extract_with_proxy( the_thread ); _Watchdog_Remove_ticks( &the_thread->Timer ); - _Scheduler_Set_priority_if_higher( scheduler, the_thread, priority ); + _Thread_Change_priority( + the_thread, + priority, + NULL, + _Thread_Raise_real_priority_filter, + false + ); _Thread_Add_post_switch_action( the_thread, &the_thread->Life.Action ); _Thread_Ready( the_thread ); } @@ -260,9 +287,9 @@ static void _Thread_Request_life_change( scheduler = _Scheduler_Get( the_thread ); if ( the_thread == executing ) { - executing->real_priority = priority; + Priority_Control unused; - _Scheduler_Set_priority_if_higher( scheduler, the_thread, priority ); + _Thread_Set_priority( the_thread, priority, &unused, true ); _Thread_Start_life_change_for_executing( executing ); } else if ( previous_life_state == THREAD_LIFE_NORMAL ) { _Thread_Start_life_change( the_thread, scheduler, priority ); @@ -270,16 +297,11 @@ static void _Thread_Request_life_change( _Thread_Clear_state( the_thread, STATES_SUSPENDED ); if ( _Thread_Is_life_terminating( additional_life_state ) ) { - the_thread->real_priority = _Scheduler_Highest_priority_of_two( - scheduler, - the_thread->real_priority, - priority - ); - - _Scheduler_Change_priority_if_higher( - scheduler, + _Thread_Change_priority( the_thread, priority, + NULL, + _Thread_Raise_real_priority_filter, false ); } diff --git a/cpukit/score/src/threadsetpriority.c b/cpukit/score/src/threadsetpriority.c index e1ff118c7e..f6a061a281 100644 --- a/cpukit/score/src/threadsetpriority.c +++ b/cpukit/score/src/threadsetpriority.c @@ -19,14 +19,41 @@ #endif #include -#include -void _Thread_Set_priority( +static bool _Thread_Set_priority_filter( Thread_Control *the_thread, - Priority_Control new_priority + Priority_Control *new_priority_ptr, + void *arg ) { - the_thread->current_priority = new_priority; + Priority_Control current_priority; + Priority_Control new_priority; + Priority_Control *old_priority_ptr; + + current_priority = the_thread->current_priority; + new_priority = *new_priority_ptr; + + old_priority_ptr = arg; + *old_priority_ptr = current_priority; + + the_thread->real_priority = new_priority; + + return _Thread_Priority_less_than( current_priority, new_priority ) + || !_Thread_Owns_resources( the_thread ); +} - _Scheduler_Update_priority( the_thread, new_priority ); +void _Thread_Set_priority( + Thread_Control *the_thread, + Priority_Control new_priority, + Priority_Control *old_priority, + bool prepend_it +) +{ + _Thread_Change_priority( + the_thread, + new_priority, + old_priority, + _Thread_Set_priority_filter, + prepend_it + ); } diff --git a/testsuites/smptests/smpscheduler03/init.c b/testsuites/smptests/smpscheduler03/init.c index d919482c8a..d54b6aacc3 100644 --- a/testsuites/smptests/smpscheduler03/init.c +++ b/testsuites/smptests/smpscheduler03/init.c @@ -40,6 +40,30 @@ typedef struct { static test_context test_instance; +static bool change_priority_filter( + Thread_Control *thread, + Priority_Control *new_priority, + void *arg +) +{ + return thread->current_priority != *new_priority; +} + +static void change_priority( + Thread_Control *thread, + Priority_Control new_priority, + bool prepend_it +) +{ + _Thread_Change_priority( + thread, + new_priority, + NULL, + change_priority_filter, + prepend_it + ); +} + static void barrier_wait(test_context *ctx) { rtems_status_code sc; @@ -97,10 +121,10 @@ static void test_case_change_priority( { switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: - _Thread_Change_priority(executing, 1, true); + change_priority(executing, 1, true); break; case SCHEDULER_SMP_NODE_READY: - _Thread_Change_priority(executing, 4, true); + change_priority(executing, 4, true); break; default: rtems_test_assert(0); @@ -108,7 +132,7 @@ static void test_case_change_priority( } rtems_test_assert(node->state == start_state); - _Thread_Change_priority(executing, prio, prepend_it); + change_priority(executing, prio, prepend_it); rtems_test_assert(node->state == new_state); } @@ -153,7 +177,7 @@ static void test_change_priority(void) } } - _Thread_Change_priority(executing, 1, true); + change_priority(executing, 1, true); rtems_test_assert(node->state == SCHEDULER_SMP_NODE_SCHEDULED); _Thread_Enable_dispatch(); @@ -199,10 +223,10 @@ static void test_case_change_priority_op( switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: - _Thread_Change_priority(executing, 1, true); + change_priority(executing, 1, true); break; case SCHEDULER_SMP_NODE_READY: - _Thread_Change_priority(executing, 4, true); + change_priority(executing, 4, true); break; default: rtems_test_assert(0); @@ -266,7 +290,7 @@ static void test_change_priority_op(void) } } - _Thread_Change_priority(executing, 1, true); + change_priority(executing, 1, true); rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); _Thread_Enable_dispatch(); @@ -298,19 +322,19 @@ static void test_case_yield_op( { Thread_Control *needs_help; - _Thread_Change_priority(executing, 4, false); - _Thread_Change_priority(other, 4, false); + change_priority(executing, 4, false); + change_priority(other, 4, false); switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: switch (new_state) { case SCHEDULER_SMP_NODE_SCHEDULED: - _Thread_Change_priority(executing, 2, false); - _Thread_Change_priority(other, 3, false); + change_priority(executing, 2, false); + change_priority(other, 3, false); break; case SCHEDULER_SMP_NODE_READY: - _Thread_Change_priority(executing, 2, false); - _Thread_Change_priority(other, 2, false); + change_priority(executing, 2, false); + change_priority(other, 2, false); break; default: rtems_test_assert(0); @@ -323,8 +347,8 @@ static void test_case_yield_op( rtems_test_assert(0); break; case SCHEDULER_SMP_NODE_READY: - _Thread_Change_priority(executing, 3, false); - _Thread_Change_priority(other, 2, false); + change_priority(executing, 3, false); + change_priority(other, 2, false); break; default: rtems_test_assert(0); @@ -393,7 +417,7 @@ static void test_yield_op(void) } } - _Thread_Change_priority(executing, 1, true); + change_priority(executing, 1, true); rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); _Thread_Enable_dispatch(); @@ -436,11 +460,11 @@ static void test_case_unblock_op( switch (new_state) { case SCHEDULER_SMP_NODE_SCHEDULED: - _Thread_Change_priority(executing, 2, false); + change_priority(executing, 2, false); rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); break; case SCHEDULER_SMP_NODE_READY: - _Thread_Change_priority(executing, 4, false); + change_priority(executing, 4, false); rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_READY); break; default: @@ -494,7 +518,7 @@ static void test_unblock_op(void) ); } - _Thread_Change_priority(executing, 1, true); + change_priority(executing, 1, true); rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); _Thread_Enable_dispatch(); -- cgit v1.2.3 From 80f376db6c32bb4d01c93f5a2d7044798262d359 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 6 May 2015 14:25:09 +0200 Subject: score: Remove Giant lock in rtems_clock_tick() Update #2307. --- cpukit/rtems/src/clocktick.c | 11 +---------- testsuites/sptests/sp37/init.c | 4 ---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/cpukit/rtems/src/clocktick.c b/cpukit/rtems/src/clocktick.c index a026b44494..fe49e9a059 100644 --- a/cpukit/rtems/src/clocktick.c +++ b/cpukit/rtems/src/clocktick.c @@ -26,23 +26,14 @@ rtems_status_code rtems_clock_tick( void ) { -#if defined( RTEMS_SMP ) - _Thread_Disable_dispatch(); -#endif - _TOD_Tickle_ticks(); _Watchdog_Tickle_ticks(); _Scheduler_Tick(); -#if defined( RTEMS_SMP ) - _Thread_Enable_dispatch(); -#else - if ( _Thread_Is_context_switch_necessary() && - _Thread_Dispatch_is_enabled() ) + if ( _Thread_Dispatch_is_enabled() ) _Thread_Dispatch(); -#endif return RTEMS_SUCCESSFUL; } diff --git a/testsuites/sptests/sp37/init.c b/testsuites/sptests/sp37/init.c index aaaf68426b..647485e555 100644 --- a/testsuites/sptests/sp37/init.c +++ b/testsuites/sptests/sp37/init.c @@ -431,11 +431,7 @@ rtems_timer_service_routine test_unblock_task( _Thread_Disable_dispatch(); status = rtems_task_resume( blocked_task_id ); _Thread_Unnest_dispatch(); -#if defined( RTEMS_SMP ) - directive_failed_with_level( status, "rtems_task_resume", 1 ); -#else directive_failed( status, "rtems_task_resume" ); -#endif } rtems_task Init( -- cgit v1.2.3 From a816f08478e2fe395062a8114c0654d0624906ae Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 7 May 2015 14:02:46 +0200 Subject: score: Fine grained locking for MrsP Update #2273. --- cpukit/rtems/src/semobtain.c | 7 +- cpukit/rtems/src/semrelease.c | 10 +- cpukit/score/include/rtems/score/mrsp.h | 27 ++++-- cpukit/score/include/rtems/score/mrspimpl.h | 136 ++++++++++++++++++++-------- cpukit/score/src/schedulerchangeroot.c | 5 - 5 files changed, 124 insertions(+), 61 deletions(-) diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index 1ebc98bdb7..bda39fa80e 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -59,16 +59,13 @@ rtems_status_code rtems_semaphore_obtain( if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { MRSP_Status mrsp_status; - _Thread_Disable_dispatch(); - _ISR_lock_ISR_enable( &lock_context ); mrsp_status = _MRSP_Obtain( &the_semaphore->Core_control.mrsp, executing, wait, - timeout + timeout, + &lock_context ); - _Thread_Enable_dispatch(); - _Objects_Put_for_get_isr_disable( &the_semaphore->Object ); return _Semaphore_Translate_MRSP_status_code( mrsp_status ); } else #endif diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c index 7e4b98e7de..5d41b6cfae 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -75,13 +75,13 @@ rtems_status_code rtems_semaphore_release( attribute_set = the_semaphore->attribute_set; #if defined(RTEMS_SMP) if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { - _Thread_Disable_dispatch(); - _ISR_lock_ISR_enable( &lock_context ); - MRSP_Status mrsp_status = _MRSP_Release( + MRSP_Status mrsp_status; + + mrsp_status = _MRSP_Release( &the_semaphore->Core_control.mrsp, - _Thread_Get_executing() + _Thread_Executing, + &lock_context ); - _Thread_Enable_dispatch(); return _Semaphore_Translate_MRSP_status_code( mrsp_status ); } else #endif diff --git a/cpukit/score/include/rtems/score/mrsp.h b/cpukit/score/include/rtems/score/mrsp.h index 9eb2887766..08f96ac4ac 100644 --- a/cpukit/score/include/rtems/score/mrsp.h +++ b/cpukit/score/include/rtems/score/mrsp.h @@ -20,6 +20,7 @@ #if defined(RTEMS_SMP) #include +#include #include #include @@ -75,23 +76,29 @@ typedef enum { MRSP_WAIT_FOR_OWNERSHIP = 255 } MRSP_Status; +typedef struct MRSP_Control MRSP_Control; + /** * @brief MrsP rival. * * The rivals are used by threads waiting for resource ownership. They are - * registered in the MRSP control block. + * registered in the MrsP control block. */ typedef struct { /** - * @brief The node for registration in the MRSP rival chain. + * @brief The node for registration in the MrsP rival chain. * - * The chain operations are protected by the Giant lock and disabled - * interrupts. + * The chain operations are protected by the MrsP control lock. * * @see MRSP_Control::Rivals. */ Chain_Node Node; + /** + * @brief The corresponding MrsP control block. + */ + MRSP_Control *resource; + /** * @brief Identification of the rival thread. */ @@ -118,8 +125,7 @@ typedef struct { * * Initially the status is set to MRSP_WAIT_FOR_OWNERSHIP. The rival will * busy wait until a status change happens. This can be MRSP_SUCCESSFUL or - * MRSP_TIMEOUT. State changes are protected by the Giant lock and disabled - * interrupts. + * MRSP_TIMEOUT. State changes are protected by the MrsP control lock. */ volatile MRSP_Status status; } MRSP_Rival; @@ -127,7 +133,7 @@ typedef struct { /** * @brief MrsP control block. */ -typedef struct { +struct MRSP_Control { /** * @brief Basic resource control. */ @@ -140,6 +146,11 @@ typedef struct { */ Chain_Control Rivals; + /** + * @brief Lock to protect the resource dependency tree. + */ + ISR_LOCK_MEMBER( Lock ) + /** * @brief The initial priority of the owner before it was elevated to the * ceiling priority. @@ -150,7 +161,7 @@ typedef struct { * @brief One ceiling priority per scheduler instance. */ Priority_Control *ceiling_priorities; -} MRSP_Control; +}; /** @} */ diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h index 05aee42a22..82ecb07047 100644 --- a/cpukit/score/include/rtems/score/mrspimpl.h +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -36,6 +36,23 @@ extern "C" { * @{ */ +/* + * FIXME: Operations with the resource dependency tree are protected by the + * global scheduler lock. Since the scheduler lock should be scheduler + * instance specific in the future this will only work temporarily. A more + * sophisticated locking strategy is necessary. + */ + +RTEMS_INLINE_ROUTINE void _MRSP_Giant_acquire( ISR_lock_Context *lock_context ) +{ + _ISR_lock_Acquire( &_Scheduler_Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _MRSP_Giant_release( ISR_lock_Context *lock_context ) +{ + _ISR_lock_Release( &_Scheduler_Lock, lock_context ); +} + RTEMS_INLINE_ROUTINE bool _MRSP_Restore_priority_filter( Thread_Control *thread, Priority_Control *new_priority, @@ -74,14 +91,23 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership( MRSP_Control *mrsp, Thread_Control *new_owner, Priority_Control initial_priority, - Priority_Control ceiling_priority + Priority_Control ceiling_priority, + ISR_lock_Context *lock_context ) { + Per_CPU_Control *cpu_self; + _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource ); _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node ); mrsp->initial_priority_of_owner = initial_priority; - _Thread_Raise_priority( new_owner, ceiling_priority ); _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER ); + + cpu_self = _Thread_Dispatch_disable_critical(); + _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); + + _Thread_Raise_priority( new_owner, ceiling_priority ); + + _Thread_Dispatch_enable( cpu_self ); } RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize( @@ -111,6 +137,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize( _Resource_Initialize( &mrsp->Resource ); _Chain_Initialize_empty( &mrsp->Rivals ); + _ISR_lock_Initialize( &mrsp->Lock, "MrsP" ); return MRSP_SUCCESSFUL; } @@ -138,27 +165,32 @@ RTEMS_INLINE_ROUTINE void _MRSP_Timeout( ) { MRSP_Rival *rival = arg; + MRSP_Control *mrsp = rival->resource; Thread_Control *thread = rival->thread; - ISR_Level level; + ISR_lock_Context lock_context; (void) id; - _ISR_Disable( level ); + _ISR_lock_ISR_disable_and_acquire( &mrsp->Lock, &lock_context ); if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) { - rival->status = MRSP_TIMEOUT; + ISR_lock_Context giant_lock_context; + + _MRSP_Giant_acquire( &giant_lock_context ); _Chain_Extract_unprotected( &rival->Node ); _Resource_Node_extract( &thread->Resource_node ); _Resource_Node_set_dependency( &thread->Resource_node, NULL ); - - _ISR_Enable( level ); - _Scheduler_Thread_change_help_state( thread, rival->initial_help_state ); _Scheduler_Thread_change_resource_root( thread, thread ); - _MRSP_Restore_priority( thread, rival->initial_priority ); + + _MRSP_Giant_release( &giant_lock_context ); + + rival->status = MRSP_TIMEOUT; + + _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context ); } else { - _ISR_Enable( level ); + _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context ); } } @@ -168,35 +200,41 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( Thread_Control *executing, Priority_Control initial_priority, Priority_Control ceiling_priority, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { MRSP_Status status; MRSP_Rival rival; bool initial_life_protection; - ISR_Level level; + Per_CPU_Control *cpu_self; + ISR_lock_Context giant_lock_context; rival.thread = executing; + rival.resource = mrsp; rival.initial_priority = initial_priority; + + _MRSP_Giant_acquire( &giant_lock_context ); + rival.initial_help_state = _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL ); rival.status = MRSP_WAIT_FOR_OWNERSHIP; - _Thread_Raise_priority( executing, ceiling_priority ); - - _ISR_Disable( level ); - _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node ); _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node ); _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource ); - - _ISR_Enable( level ); - _Scheduler_Thread_change_resource_root( executing, THREAD_RESOURCE_NODE_TO_THREAD( _Resource_Node_get_root( owner ) ) ); + _MRSP_Giant_release( &giant_lock_context ); + + cpu_self = _Thread_Dispatch_disable_critical(); + _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); + + _Thread_Raise_priority( executing, ceiling_priority ); + if ( timeout > 0 ) { _Watchdog_Initialize( &executing->Timer, @@ -208,7 +246,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( } initial_life_protection = _Thread_Set_life_protection( true ); - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); _Assert( _Debug_Is_thread_dispatching_allowed() ); @@ -217,11 +255,14 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( status = rival.status; } while ( status == MRSP_WAIT_FOR_OWNERSHIP ); - _Thread_Disable_dispatch(); _Thread_Set_life_protection( initial_life_protection ); if ( timeout > 0 ) { _Watchdog_Remove_ticks( &executing->Timer ); + + if ( status == MRSP_TIMEOUT ) { + _MRSP_Restore_priority( executing, initial_priority ); + } } return status; @@ -231,7 +272,8 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain( MRSP_Control *mrsp, Thread_Control *executing, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { MRSP_Status status; @@ -247,31 +289,37 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain( Resource_Node *owner; if ( !priority_ok) { + _ISR_lock_ISR_enable( lock_context ); return MRSP_INVALID_PRIORITY; } + _ISR_lock_Acquire( &mrsp->Lock, lock_context ); owner = _Resource_Get_owner( &mrsp->Resource ); if ( owner == NULL ) { _MRSP_Claim_ownership( mrsp, executing, initial_priority, - ceiling_priority + ceiling_priority, + lock_context ); status = MRSP_SUCCESSFUL; - } else if ( _Resource_Node_get_root( owner ) == &executing->Resource_node ) { - /* Nested access or deadlock */ - status = MRSP_UNSATISFIED; - } else if ( wait ) { + } else if ( + wait + && _Resource_Node_get_root( owner ) != &executing->Resource_node + ) { status = _MRSP_Wait_for_ownership( mrsp, owner, executing, initial_priority, ceiling_priority, - timeout + timeout, + lock_context ); } else { + _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); + /* Not available, nested access or deadlock */ status = MRSP_UNSATISFIED; } @@ -279,13 +327,17 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain( } RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( - MRSP_Control *mrsp, - Thread_Control *executing + MRSP_Control *mrsp, + Thread_Control *executing, + ISR_lock_Context *lock_context ) { - ISR_Level level; + Priority_Control initial_priority; + Per_CPU_Control *cpu_self; + ISR_lock_Context giant_lock_context; if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) { + _ISR_lock_ISR_enable( lock_context ); return MRSP_NOT_OWNER_OF_RESOURCE; } @@ -295,18 +347,19 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( &executing->Resource_node ) ) { + _ISR_lock_ISR_enable( lock_context ); return MRSP_INCORRECT_STATE; } - _MRSP_Restore_priority( executing, mrsp->initial_priority_of_owner ); + initial_priority = mrsp->initial_priority_of_owner; + + _ISR_lock_Acquire( &mrsp->Lock, lock_context ); - _ISR_Disable( level ); + _MRSP_Giant_acquire( &giant_lock_context ); _Resource_Extract( &mrsp->Resource ); if ( _Chain_Is_empty( &mrsp->Rivals ) ) { - _ISR_Enable( level ); - _Resource_Set_owner( &mrsp->Resource, NULL ); } else { MRSP_Rival *rival = (MRSP_Rival *) @@ -325,9 +378,6 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( _Resource_Node_set_dependency( &new_owner->Resource_node, NULL ); _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource ); _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node ); - - _ISR_Enable( level ); - _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER ); _Scheduler_Thread_change_resource_root( new_owner, new_owner ); } @@ -336,6 +386,15 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF ); } + _MRSP_Giant_release( &giant_lock_context ); + + cpu_self = _Thread_Dispatch_disable_critical(); + _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); + + _MRSP_Restore_priority( executing, initial_priority ); + + _Thread_Dispatch_enable( cpu_self ); + return MRSP_SUCCESSFUL; } @@ -345,6 +404,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Destroy( MRSP_Control *mrsp ) return MRSP_RESOUCE_IN_USE; } + _ISR_lock_Destroy( &mrsp->Lock ); _Workspace_Free( mrsp->ceiling_priorities ); return MRSP_SUCCESSFUL; diff --git a/cpukit/score/src/schedulerchangeroot.c b/cpukit/score/src/schedulerchangeroot.c index f731117b4c..d036fd8a8b 100644 --- a/cpukit/score/src/schedulerchangeroot.c +++ b/cpukit/score/src/schedulerchangeroot.c @@ -61,9 +61,6 @@ void _Scheduler_Thread_change_resource_root( Thread_Control *offers_help = top; Scheduler_Node *offers_help_node; Thread_Control *offers_help_too; - ISR_Level level; - - _ISR_Disable( level ); offers_help_node = _Scheduler_Thread_get_node( offers_help ); offers_help_too = _Scheduler_Node_get_owner( offers_help_node ); @@ -80,6 +77,4 @@ void _Scheduler_Thread_change_resource_root( if ( ctx.needs_help != NULL ) { _Scheduler_Ask_for_help( ctx.needs_help ); } - - _ISR_Enable( level ); } -- cgit v1.2.3 From 7a70a09260acc21e5bc46988fc09f22867781186 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 May 2015 10:00:50 +0200 Subject: score: Delete _Objects_Put_for_get_isr_disable() This function is superfluous due to the introduction of fine grained locking. --- cpukit/rtems/src/eventsend.c | 1 - cpukit/rtems/src/systemeventsend.c | 1 - cpukit/score/include/rtems/score/objectimpl.h | 10 ---------- 3 files changed, 12 deletions(-) diff --git a/cpukit/rtems/src/eventsend.c b/cpukit/rtems/src/eventsend.c index c9e81fb95f..23eed740a8 100644 --- a/cpukit/rtems/src/eventsend.c +++ b/cpukit/rtems/src/eventsend.c @@ -44,7 +44,6 @@ rtems_status_code rtems_event_send( THREAD_WAIT_CLASS_EVENT, &lock_context ); - _Objects_Put_for_get_isr_disable( &thread->Object ); sc = RTEMS_SUCCESSFUL; break; #ifdef RTEMS_MULTIPROCESSING diff --git a/cpukit/rtems/src/systemeventsend.c b/cpukit/rtems/src/systemeventsend.c index 1892c13fe7..3c821c9ef9 100644 --- a/cpukit/rtems/src/systemeventsend.c +++ b/cpukit/rtems/src/systemeventsend.c @@ -50,7 +50,6 @@ rtems_status_code rtems_event_system_send( THREAD_WAIT_CLASS_SYSTEM_EVENT, &lock_context ); - _Objects_Put_for_get_isr_disable( &thread->Object ); sc = RTEMS_SUCCESSFUL; break; #ifdef RTEMS_MULTIPROCESSING diff --git a/cpukit/score/include/rtems/score/objectimpl.h b/cpukit/score/include/rtems/score/objectimpl.h index 4080a249cf..a5a3b7ef5f 100644 --- a/cpukit/score/include/rtems/score/objectimpl.h +++ b/cpukit/score/include/rtems/score/objectimpl.h @@ -990,16 +990,6 @@ RTEMS_INLINE_ROUTINE void _Objects_Put_without_thread_dispatch( _Thread_Unnest_dispatch(); } -/** - * @brief Puts back an object obtained with _Objects_Get_isr_disable(). - */ -RTEMS_INLINE_ROUTINE void _Objects_Put_for_get_isr_disable( - Objects_Control *the_object -) -{ - (void) the_object; -} - /** * @brief Locks the object allocator mutex. * -- cgit v1.2.3 From 9052f88b1647c7ba77e2159b0012e014ab165b2b Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 11 May 2015 10:14:31 +0200 Subject: score: Do not inline SMP lock if profiling enabled This reduces the code size drastically. --- cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/smplock.h | 57 ++++++++++++++++++++++++- cpukit/score/src/smplock.c | 68 ++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 cpukit/score/src/smplock.c diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index cede673bb6..714bd6663b 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -138,6 +138,7 @@ libscore_a_SOURCES += src/schedulerprioritysmp.c libscore_a_SOURCES += src/schedulersimplesmp.c libscore_a_SOURCES += src/schedulersmpdebug.c libscore_a_SOURCES += src/smp.c +libscore_a_SOURCES += src/smplock.c libscore_a_SOURCES += src/smpmulticastaction.c libscore_a_SOURCES += src/cpuset.c libscore_a_SOURCES += src/cpusetprintsupport.c diff --git a/cpukit/score/include/rtems/score/smplock.h b/cpukit/score/include/rtems/score/smplock.h index 5eb6ef344f..50a0662ca9 100644 --- a/cpukit/score/include/rtems/score/smplock.h +++ b/cpukit/score/include/rtems/score/smplock.h @@ -10,7 +10,7 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2013-2014 embedded brains GmbH + * Copyright (c) 2013-2015 embedded brains GmbH * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -32,6 +32,10 @@ #include #endif +#if defined( RTEMS_PROFILING ) +#define RTEMS_SMP_LOCK_DO_NOT_INLINE +#endif + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -368,7 +372,16 @@ typedef struct { * @param[in] name The name for the SMP lock statistics. This name must be * persistent throughout the life time of this statistics block. */ +#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) +void _SMP_lock_Initialize( + SMP_lock_Control *lock, + const char *name +); + +static inline void _SMP_lock_Initialize_body( +#else static inline void _SMP_lock_Initialize( +#endif SMP_lock_Control *lock, const char *name ) @@ -383,7 +396,13 @@ static inline void _SMP_lock_Initialize( * * @param[in,out] lock The SMP lock control. */ +#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) +void _SMP_lock_Destroy( SMP_lock_Control *lock ); + +static inline void _SMP_lock_Destroy_body( SMP_lock_Control *lock ) +#else static inline void _SMP_lock_Destroy( SMP_lock_Control *lock ) +#endif { _SMP_ticket_lock_Destroy( &lock->ticket_lock ); } @@ -399,7 +418,16 @@ static inline void _SMP_lock_Destroy( SMP_lock_Control *lock ) * @param[in,out] context The local SMP lock context for an acquire and release * pair. */ +#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) +void _SMP_lock_Acquire( + SMP_lock_Control *lock, + SMP_lock_Context *context +); + +static inline void _SMP_lock_Acquire_body( +#else static inline void _SMP_lock_Acquire( +#endif SMP_lock_Control *lock, SMP_lock_Context *context ) @@ -415,7 +443,16 @@ static inline void _SMP_lock_Acquire( * @param[in,out] context The local SMP lock context for an acquire and release * pair. */ +#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) +void _SMP_lock_Release( + SMP_lock_Control *lock, + SMP_lock_Context *context +); + +static inline void _SMP_lock_Release_body( +#else static inline void _SMP_lock_Release( +#endif SMP_lock_Control *lock, SMP_lock_Context *context ) @@ -431,7 +468,16 @@ static inline void _SMP_lock_Release( * @param[in,out] context The local SMP lock context for an acquire and release * pair. */ +#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) +void _SMP_lock_ISR_disable_and_acquire( + SMP_lock_Control *lock, + SMP_lock_Context *context +); + +static inline void _SMP_lock_ISR_disable_and_acquire_body( +#else static inline void _SMP_lock_ISR_disable_and_acquire( +#endif SMP_lock_Control *lock, SMP_lock_Context *context ) @@ -447,7 +493,16 @@ static inline void _SMP_lock_ISR_disable_and_acquire( * @param[in,out] context The local SMP lock context for an acquire and release * pair. */ +#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) +void _SMP_lock_Release_and_ISR_enable( + SMP_lock_Control *lock, + SMP_lock_Context *context +); + +static inline void _SMP_lock_Release_and_ISR_enable_body( +#else static inline void _SMP_lock_Release_and_ISR_enable( +#endif SMP_lock_Control *lock, SMP_lock_Context *context ) diff --git a/cpukit/score/src/smplock.c b/cpukit/score/src/smplock.c new file mode 100644 index 0000000000..14400917ef --- /dev/null +++ b/cpukit/score/src/smplock.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 + +#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE) + +void _SMP_lock_Initialize( + SMP_lock_Control *lock, + const char *name +) +{ + _SMP_lock_Initialize_body( lock, name ); +} + +void _SMP_lock_Destroy( SMP_lock_Control *lock ) +{ + _SMP_lock_Destroy_body( lock ); +} + +void _SMP_lock_Acquire( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ + _SMP_lock_Acquire_body( lock, context ); +} + +void _SMP_lock_Release( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ + _SMP_lock_Release_body( lock, context ); +} + +void _SMP_lock_ISR_disable_and_acquire( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ + _SMP_lock_ISR_disable_and_acquire_body( lock, context ); +} + +void _SMP_lock_Release_and_ISR_enable( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ + _SMP_lock_Release_and_ISR_enable_body( lock, context ); +} + +#endif /* defined(RTEMS_SMP_LOCK_DO_NOT_INLINE) */ -- cgit v1.2.3 From d8752860e50a495f5d886275b7eb407aa9ec8b1c Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 11 May 2015 14:56:12 +0200 Subject: score: Add static initializers for thread queues --- cpukit/score/include/rtems/score/threadqimpl.h | 34 ++++++++++++++++++++++++++ testsuites/sptests/spthreadq01/init.c | 14 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 79fc810b9b..32217ad73e 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -20,6 +20,8 @@ #define _RTEMS_SCORE_THREADQIMPL_H #include +#include +#include #include #ifdef __cplusplus @@ -342,6 +344,38 @@ void _Thread_queue_Initialize( Thread_queue_Disciplines the_discipline ); +#if defined(RTEMS_SMP) + #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \ + .Queues = { \ + .Fifo = CHAIN_INITIALIZER_EMPTY( designator.Queues.Fifo ) \ + }, \ + .operations = &_Thread_queue_Operations_FIFO, \ + .Lock = ISR_LOCK_INITIALIZER( name ) \ + } + + #define THREAD_QUEUE_PRIORIY_INITIALIZER( designator, name ) { \ + .Queues = { \ + .Priority = RBTREE_INITIALIZER_EMPTY( designator.Queues.Priority ) \ + }, \ + .operations = &_Thread_queue_Operations_priority, \ + .Lock = ISR_LOCK_INITIALIZER( name ) \ + } +#else + #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \ + .Queues = { \ + .Fifo = CHAIN_INITIALIZER_EMPTY( designator.Queues.Fifo ) \ + }, \ + .operations = &_Thread_queue_Operations_FIFO \ + } + + #define THREAD_QUEUE_PRIORIY_INITIALIZER( designator, name ) { \ + .Queues = { \ + .Priority = RBTREE_INITIALIZER_EMPTY( designator.Queues.Priority ) \ + }, \ + .operations = &_Thread_queue_Operations_priority \ + } +#endif + RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy( Thread_queue_Control *the_thread_queue ) diff --git a/testsuites/sptests/spthreadq01/init.c b/testsuites/sptests/spthreadq01/init.c index 5add92bb5d..ce47760e2d 100644 --- a/testsuites/sptests/spthreadq01/init.c +++ b/testsuites/sptests/spthreadq01/init.c @@ -18,6 +18,12 @@ const char rtems_test_name[] = "SPTHREADQ 1"; +static Thread_queue_Control fifo_queue = + THREAD_QUEUE_FIFO_INITIALIZER( fifo_queue, "FIFO" ); + +static Thread_queue_Control prio_queue = + THREAD_QUEUE_PRIORIY_INITIALIZER( prio_queue, "Prio" ); + static rtems_task Init( rtems_task_argument ignored ) @@ -30,6 +36,14 @@ static rtems_task Init( _Thread_Enable_dispatch(); /* is there more to check? */ + rtems_test_assert( _Chain_Is_empty( &fifo_queue.Queues.Fifo ) ); + rtems_test_assert( fifo_queue.operations == &_Thread_queue_Operations_FIFO ); + + rtems_test_assert( _RBTree_Is_empty( &fifo_queue.Queues.Priority ) ); + rtems_test_assert( + prio_queue.operations == &_Thread_queue_Operations_priority + ); + TEST_END(); rtems_test_exit(0); } -- cgit v1.2.3 From aa05cfbb3d6309ec45b69f34d0870465fe30b74c Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 11 May 2015 14:56:49 +0200 Subject: score: Replace _Thread_Delay_ended() Use _Thread_Timeout() instead. Use pseudo thread queue for nanosleep() to deal with signals. Close #2130. --- cpukit/posix/src/nanosleep.c | 35 +++++++++++++++--------------- cpukit/posix/src/psignalunblockthread.c | 11 +--------- cpukit/rtems/src/taskwakeafter.c | 10 +++++---- cpukit/rtems/src/taskwakewhen.c | 8 ++++--- cpukit/score/Makefile.am | 2 +- cpukit/score/src/threaddelayended.c | 38 --------------------------------- 6 files changed, 30 insertions(+), 74 deletions(-) delete mode 100644 cpukit/score/src/threaddelayended.c diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c index 39ae84d3e4..46697ae8fc 100644 --- a/cpukit/posix/src/nanosleep.c +++ b/cpukit/posix/src/nanosleep.c @@ -23,9 +23,13 @@ #include #include +#include #include #include +static Thread_queue_Control _Nanosleep_Pseudo_queue = + THREAD_QUEUE_FIFO_INITIALIZER( _Nanosleep_Pseudo_queue, "Nanosleep" ); + /* * 14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269 */ @@ -38,7 +42,8 @@ int nanosleep( * It is critical to obtain the executing thread after thread dispatching is * disabled on SMP configurations. */ - Thread_Control *executing; + Thread_Control *executing; + Per_CPU_Control *cpu_self; Watchdog_Interval ticks; Watchdog_Interval elapsed; @@ -58,16 +63,17 @@ int nanosleep( */ ticks = _Timespec_To_ticks( rqtp ); + executing = _Thread_Get_executing(); + /* * A nanosleep for zero time is implemented as a yield. * This behavior is also beyond the POSIX specification but is * consistent with the RTEMS API and yields desirable behavior. */ if ( !ticks ) { - _Thread_Disable_dispatch(); - executing = _Thread_Executing; + cpu_self = _Thread_Dispatch_disable(); _Thread_Yield( executing ); - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); if ( rmtp ) { rmtp->tv_sec = 0; rmtp->tv_nsec = 0; @@ -78,20 +84,13 @@ int nanosleep( /* * Block for the desired amount of time */ - _Thread_Disable_dispatch(); - executing = _Thread_Executing; - _Thread_Set_state( - executing, - STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL - ); - _Watchdog_Initialize( - &executing->Timer, - _Thread_Delay_ended, - 0, - executing - ); - _Watchdog_Insert_ticks( &executing->Timer, ticks ); - _Thread_Enable_dispatch(); + _Thread_queue_Enqueue( + &_Nanosleep_Pseudo_queue, + executing, + STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL, + ticks, + 0 + ); /* * Calculate the time that passed while we were sleeping and how diff --git a/cpukit/posix/src/psignalunblockthread.c b/cpukit/posix/src/psignalunblockthread.c index 3b310a90b7..200e9e714b 100644 --- a/cpukit/posix/src/psignalunblockthread.c +++ b/cpukit/posix/src/psignalunblockthread.c @@ -110,16 +110,7 @@ bool _POSIX_signals_Unblock_thread( if ( _States_Is_interruptible_by_signal( the_thread->current_state ) ) { the_thread->Wait.return_code = EINTR; - /* - * In pthread_cond_wait, a thread will be blocking on a thread - * queue, but is also interruptible by a POSIX signal. - */ - if ( _States_Is_delaying(the_thread->current_state) ) { - _Watchdog_Remove_ticks( &the_thread->Timer ); - _Thread_Unblock( the_thread ); - } else { - _Thread_queue_Extract_with_proxy( the_thread ); - } + _Thread_queue_Extract_with_proxy( the_thread ); } } return _POSIX_signals_Unblock_thread_done( the_thread, api, false ); diff --git a/cpukit/rtems/src/taskwakeafter.c b/cpukit/rtems/src/taskwakeafter.c index 6f0322723a..b7f328f5bc 100644 --- a/cpukit/rtems/src/taskwakeafter.c +++ b/cpukit/rtems/src/taskwakeafter.c @@ -30,23 +30,25 @@ rtems_status_code rtems_task_wake_after( * It is critical to obtain the executing thread after thread dispatching is * disabled on SMP configurations. */ - Thread_Control *executing; + Thread_Control *executing; + Per_CPU_Control *cpu_self; - _Thread_Disable_dispatch(); + cpu_self = _Thread_Dispatch_disable(); executing = _Thread_Executing; if ( ticks == 0 ) { _Thread_Yield( executing ); } else { _Thread_Set_state( executing, STATES_DELAYING ); + _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); _Watchdog_Initialize( &executing->Timer, - _Thread_Delay_ended, + _Thread_Timeout, 0, executing ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); } - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; } diff --git a/cpukit/rtems/src/taskwakewhen.c b/cpukit/rtems/src/taskwakewhen.c index a1fc15f047..cf0b303cd3 100644 --- a/cpukit/rtems/src/taskwakewhen.c +++ b/cpukit/rtems/src/taskwakewhen.c @@ -30,6 +30,7 @@ rtems_status_code rtems_task_wake_when( { Watchdog_Interval seconds; Thread_Control *executing; + Per_CPU_Control *cpu_self; if ( !_TOD_Is_set() ) return RTEMS_NOT_DEFINED; @@ -47,12 +48,13 @@ rtems_status_code rtems_task_wake_when( if ( seconds <= _TOD_Seconds_since_epoch() ) return RTEMS_INVALID_CLOCK; - _Thread_Disable_dispatch(); + cpu_self = _Thread_Dispatch_disable(); 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_Delay_ended, + _Thread_Timeout, 0, executing ); @@ -60,6 +62,6 @@ rtems_status_code rtems_task_wake_when( &executing->Timer, seconds - _TOD_Seconds_since_epoch() ); - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; } diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 714bd6663b..b6b7c9fa74 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -280,7 +280,7 @@ libscore_a_SOURCES += src/rbtree.c \ ## THREAD_C_FILES libscore_a_SOURCES += src/thread.c src/threadchangepriority.c \ src/threadclearstate.c src/threadcreateidle.c \ - src/threaddelayended.c src/threaddispatch.c \ + src/threaddispatch.c \ src/threadenabledispatch.c src/threaddisabledispatch.c \ src/threadget.c src/threadhandler.c src/threadinitialize.c \ src/threadloadenv.c \ diff --git a/cpukit/score/src/threaddelayended.c b/cpukit/score/src/threaddelayended.c deleted file mode 100644 index 95dae7d0fa..0000000000 --- a/cpukit/score/src/threaddelayended.c +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file - * - * @brief End the Delay of a Thread - * @ingroup ScoreThread - */ - -/* - * 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 - -void _Thread_Delay_ended( - Objects_Id id, - void *arg -) -{ - Thread_Control *the_thread = arg; - - (void) id; - - _Thread_Clear_state( - the_thread, - STATES_DELAYING - | STATES_WAITING_FOR_TIME - | STATES_INTERRUPTIBLE_BY_SIGNAL - ); -} -- cgit v1.2.3 From d5423295988918f45b64d50cf0b9501a56b9aa36 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 18 May 2015 11:09:14 +0200 Subject: score: _Thread_Dispatch_disable_critical() Thread dispatching is disabled in case interrupts are disabled. To get an accurate thread dispatch disabled time it is important to use the interrupt disabled instant in case a transition from an interrupt disabled section to a thread dispatch level section happens. --- cpukit/rtems/src/eventseize.c | 2 +- cpukit/rtems/src/eventsurrender.c | 2 +- cpukit/score/include/rtems/score/coremuteximpl.h | 2 +- cpukit/score/include/rtems/score/isrlock.h | 23 ++++++++++++++++++-- cpukit/score/include/rtems/score/mrspimpl.h | 6 +++--- cpukit/score/include/rtems/score/profiling.h | 21 ++++++++++++++++++ cpukit/score/include/rtems/score/threaddispatch.h | 26 +++++++++++++++-------- cpukit/score/src/threadqenqueue.c | 4 ++-- 8 files changed, 67 insertions(+), 19 deletions(-) diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index 6611a8d6f6..981c7d281c 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -84,7 +84,7 @@ void _Event_Seize( executing->Wait.return_argument = event_out; _Thread_Wait_flags_set( executing, intend_to_block ); - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_Lock_release_default( executing, lock_context ); _Giant_Acquire( cpu_self ); diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index b740721e22..a16d40e7df 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -107,7 +107,7 @@ void _Event_Surrender( if ( unblock ) { Per_CPU_Control *cpu_self; - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_Lock_release_default( the_thread, lock_context ); _Giant_Acquire( cpu_self ); diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index ca9d61df4a..f57fdfcfd5 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -489,7 +489,7 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body( if ( current > ceiling ) { Per_CPU_Control *cpu_self; - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_queue_Release( &the_mutex->Wait_queue, lock_context ); _Thread_Raise_priority( executing, ceiling ); _Thread_Dispatch_enable( cpu_self ); diff --git a/cpukit/score/include/rtems/score/isrlock.h b/cpukit/score/include/rtems/score/isrlock.h index 5a68937b4d..994eb48ed0 100644 --- a/cpukit/score/include/rtems/score/isrlock.h +++ b/cpukit/score/include/rtems/score/isrlock.h @@ -68,6 +68,12 @@ typedef struct { #else ISR_Level isr_level; #endif +#if defined( RTEMS_PROFILING ) + /** + * @brief The last interrupt disable instant in CPU counter ticks. + */ + CPU_Counter_ticks ISR_disable_instant; +#endif } ISR_lock_Context; /** @@ -304,6 +310,13 @@ typedef struct { _ISR_Flash( ( _context )->isr_level ) #endif +#if defined( RTEMS_PROFILING ) + #define _ISR_lock_ISR_disable_profile( _context ) \ + ( _context )->ISR_disable_instant = _CPU_Counter_read(); +#else + #define _ISR_lock_ISR_disable_profile( _context ) +#endif + /** * @brief Disables interrupts and saves the previous interrupt state in the ISR * lock context. @@ -316,10 +329,16 @@ typedef struct { */ #if defined( RTEMS_SMP ) #define _ISR_lock_ISR_disable( _context ) \ - _ISR_Disable_without_giant( ( _context )->Lock_context.isr_level ) + do { \ + _ISR_Disable_without_giant( ( _context )->Lock_context.isr_level ); \ + _ISR_lock_ISR_disable_profile( _context ) \ + } while ( 0 ) #else #define _ISR_lock_ISR_disable( _context ) \ - _ISR_Disable( ( _context )->isr_level ) + do { \ + _ISR_Disable( ( _context )->isr_level ); \ + _ISR_lock_ISR_disable_profile( _context ) \ + } while ( 0 ) #endif /** diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h index 82ecb07047..bc9ed4b511 100644 --- a/cpukit/score/include/rtems/score/mrspimpl.h +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -102,7 +102,7 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership( mrsp->initial_priority_of_owner = initial_priority; _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER ); - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); _Thread_Raise_priority( new_owner, ceiling_priority ); @@ -230,7 +230,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( _MRSP_Giant_release( &giant_lock_context ); - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); _Thread_Raise_priority( executing, ceiling_priority ); @@ -388,7 +388,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( _MRSP_Giant_release( &giant_lock_context ); - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context ); _MRSP_Restore_priority( executing, initial_priority ); diff --git a/cpukit/score/include/rtems/score/profiling.h b/cpukit/score/include/rtems/score/profiling.h index f5fa6cc241..a6ab283ae6 100644 --- a/cpukit/score/include/rtems/score/profiling.h +++ b/cpukit/score/include/rtems/score/profiling.h @@ -24,6 +24,7 @@ #define _RTEMS_SCORE_PROFILING #include +#include #ifdef __cplusplus extern "C" { @@ -55,6 +56,26 @@ static inline void _Profiling_Thread_dispatch_disable( #endif } +static inline void _Profiling_Thread_dispatch_disable_critical( + Per_CPU_Control *cpu, + uint32_t previous_thread_dispatch_disable_level, + const ISR_lock_Context *lock_context +) +{ +#if defined( RTEMS_PROFILING ) + if ( previous_thread_dispatch_disable_level == 0 ) { + Per_CPU_Stats *stats = &cpu->Stats; + + stats->thread_dispatch_disabled_instant = lock_context->ISR_disable_instant; + ++stats->thread_dispatch_disabled_count; + } +#else + (void) cpu; + (void) previous_thread_dispatch_disable_level; + (void) lock_context; +#endif +} + static inline void _Profiling_Thread_dispatch_enable( Per_CPU_Control *cpu, uint32_t new_thread_dispatch_disable_level diff --git a/cpukit/score/include/rtems/score/threaddispatch.h b/cpukit/score/include/rtems/score/threaddispatch.h index 89f5c0ba5b..4ef5538f7e 100644 --- a/cpukit/score/include/rtems/score/threaddispatch.h +++ b/cpukit/score/include/rtems/score/threaddispatch.h @@ -15,7 +15,7 @@ #define _RTEMS_SCORE_THREADDISPATCH_H #include -#include +#include #include #ifdef __cplusplus @@ -242,16 +242,25 @@ void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level ); * * This function does not acquire the Giant lock. * + * @param[in] lock_context The lock context of the corresponding + * _ISR_lock_ISR_disable() that started the critical section. + * * @return The current processor. */ -RTEMS_INLINE_ROUTINE Per_CPU_Control *_Thread_Dispatch_disable_critical( void ) +RTEMS_INLINE_ROUTINE Per_CPU_Control *_Thread_Dispatch_disable_critical( + const ISR_lock_Context *lock_context +) { Per_CPU_Control *cpu_self; uint32_t disable_level; cpu_self = _Per_CPU_Get(); disable_level = cpu_self->thread_dispatch_disable_level; - _Profiling_Thread_dispatch_disable( cpu_self, disable_level ); + _Profiling_Thread_dispatch_disable_critical( + cpu_self, + disable_level, + lock_context + ); cpu_self->thread_dispatch_disable_level = disable_level + 1; return cpu_self; @@ -266,18 +275,17 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Thread_Dispatch_disable_critical( void ) */ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Thread_Dispatch_disable( void ) { - Per_CPU_Control *cpu_self; + Per_CPU_Control *cpu_self; + ISR_lock_Context lock_context; #if defined( RTEMS_SMP ) || defined( RTEMS_PROFILING ) - ISR_Level level; - - _ISR_Disable_without_giant( level ); + _ISR_lock_ISR_disable( &lock_context ); #endif - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); #if defined( RTEMS_SMP ) || defined( RTEMS_PROFILING ) - _ISR_Enable_without_giant( level ); + _ISR_lock_ISR_enable( &lock_context ); #endif return cpu_self; diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 714552509e..f73fa01173 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -67,7 +67,7 @@ void _Thread_queue_Enqueue_critical( ( *operations->enqueue )( the_thread_queue, the_thread ); _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK ); - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_queue_Release( the_thread_queue, lock_context ); #if defined(RTEMS_MULTIPROCESSING) @@ -138,7 +138,7 @@ void _Thread_queue_Unblock_critical( if ( unblock ) { Per_CPU_Control *cpu_self; - cpu_self = _Thread_Dispatch_disable_critical(); + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_queue_Release( the_thread_queue, lock_context ); _Thread_queue_Unblock( the_thread ); -- cgit v1.2.3 From 20b423c6f2448c9c8aa1c2915a3d6f982302ea70 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 11 May 2015 15:02:51 +0200 Subject: psxualarm: Avoid endless signal handling Increase the ualarm timer interval to avoid endless signal handling. --- testsuites/psxtests/psxualarm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testsuites/psxtests/psxualarm/init.c b/testsuites/psxtests/psxualarm/init.c index 03e03b9649..ffe4720b50 100644 --- a/testsuites/psxtests/psxualarm/init.c +++ b/testsuites/psxtests/psxualarm/init.c @@ -86,9 +86,9 @@ void *POSIX_Init( act.sa_handler = Signal_handler; act.sa_flags = 0; sigaction( SIGALRM, &act, NULL ); - puts( "Init: ualarm in 1 us" ); + puts( "Init: ualarm in 100000 us" ); sleep(3); - result = ualarm(1,0); + result = ualarm(100000,0); rtems_test_assert( result == 0 ); status = sleep(10); -- cgit v1.2.3 From 9eb056f8c106190c94f34b5152c4bbea7e6258a0 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 11 May 2015 15:11:00 +0200 Subject: rtems: Avoid Giant lock for events --- cpukit/rtems/src/eventseize.c | 2 -- cpukit/rtems/src/eventsurrender.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index 981c7d281c..a9290b38e8 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -86,7 +86,6 @@ void _Event_Seize( cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_Lock_release_default( executing, lock_context ); - _Giant_Acquire( cpu_self ); if ( ticks ) { _Thread_Wait_set_timeout_code( executing, RTEMS_TIMEOUT ); @@ -111,6 +110,5 @@ void _Event_Seize( _Thread_Unblock( executing ); } - _Giant_Release( cpu_self ); _Thread_Dispatch_enable( cpu_self ); } diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index a16d40e7df..156586023d 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -109,12 +109,10 @@ void _Event_Surrender( cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_Lock_release_default( the_thread, lock_context ); - _Giant_Acquire( cpu_self ); _Watchdog_Remove_ticks( &the_thread->Timer ); _Thread_Unblock( the_thread ); - _Giant_Release( cpu_self ); _Thread_Dispatch_enable( cpu_self ); } else { _Thread_Lock_release_default( the_thread, lock_context ); -- cgit v1.2.3 From 33e30f393e50c03cb07606ad19a3aaf0daa4a239 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 12 May 2015 10:15:21 +0200 Subject: smptests/smpscheduler03: Restructure Restructure to avoid large maximum thread dispatch disabled times. --- testsuites/smptests/smpscheduler03/init.c | 83 ++++++++++++++++--------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/testsuites/smptests/smpscheduler03/init.c b/testsuites/smptests/smpscheduler03/init.c index d54b6aacc3..3a068a24b7 100644 --- a/testsuites/smptests/smpscheduler03/init.c +++ b/testsuites/smptests/smpscheduler03/init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014-2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -119,6 +119,10 @@ static void test_case_change_priority( Scheduler_SMP_Node_state new_state ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: change_priority(executing, 1, true); @@ -134,6 +138,11 @@ static void test_case_change_priority( change_priority(executing, prio, prepend_it); rtems_test_assert(node->state == new_state); + + change_priority(executing, 1, true); + rtems_test_assert(node->state == SCHEDULER_SMP_NODE_SCHEDULED); + + _Thread_Dispatch_enable( cpu_self ); } static const Scheduler_SMP_Node_state states[2] = { @@ -156,11 +165,8 @@ static void test_change_priority(void) size_t k; task_id = start_task(3); - - _Thread_Disable_dispatch(); - - executing = _Thread_Executing; - node = _Scheduler_SMP_Thread_get_node( executing ); + executing = _Thread_Get_executing(); + node = _Scheduler_SMP_Thread_get_node(executing); for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) { for (j = 0; j < RTEMS_ARRAY_SIZE(priorities); ++j) { @@ -177,11 +183,6 @@ static void test_change_priority(void) } } - change_priority(executing, 1, true); - rtems_test_assert(node->state == SCHEDULER_SMP_NODE_SCHEDULED); - - _Thread_Enable_dispatch(); - sc = rtems_task_delete(task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } @@ -220,6 +221,9 @@ static void test_case_change_priority_op( ) { Thread_Control *needs_help; + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: @@ -252,6 +256,11 @@ static void test_case_change_priority_op( } else { rtems_test_assert(needs_help == NULL); } + + change_priority(executing, 1, true); + rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); + + _Thread_Dispatch_enable( cpu_self ); } static void test_change_priority_op(void) @@ -266,10 +275,7 @@ static void test_change_priority_op(void) size_t k; task_id = start_task(3); - - _Thread_Disable_dispatch(); - - executing = _Thread_Executing; + executing = _Thread_Get_executing(); executing_node = _Scheduler_SMP_Thread_get_node(executing); other = get_thread_by_id(task_id); @@ -290,11 +296,6 @@ static void test_change_priority_op(void) } } - change_priority(executing, 1, true); - rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); - - _Thread_Enable_dispatch(); - sc = rtems_task_delete(task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } @@ -303,11 +304,11 @@ static Thread_Control *yield_op(Thread_Control *thread) { const Scheduler_Control *scheduler = _Scheduler_Get(thread); Thread_Control *needs_help; - ISR_Level level; + ISR_lock_Context lock_context; - _ISR_Disable( level ); + _Scheduler_Acquire(thread, &lock_context); needs_help = (*scheduler->Operations.yield)(scheduler, thread); - _ISR_Enable( level ); + _Scheduler_Release(thread, &lock_context); return needs_help; } @@ -321,6 +322,9 @@ static void test_case_yield_op( ) { Thread_Control *needs_help; + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); change_priority(executing, 4, false); change_priority(other, 4, false); @@ -379,6 +383,11 @@ static void test_case_yield_op( } else { rtems_test_assert(needs_help == NULL); } + + change_priority(executing, 1, true); + rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); + + _Thread_Dispatch_enable( cpu_self ); } static void test_yield_op(void) @@ -392,10 +401,7 @@ static void test_yield_op(void) size_t j; task_id = start_task(2); - - _Thread_Disable_dispatch(); - - executing = _Thread_Executing; + executing = _Thread_Get_executing(); executing_node = _Scheduler_SMP_Thread_get_node(executing); other = get_thread_by_id(task_id); @@ -417,11 +423,6 @@ static void test_yield_op(void) } } - change_priority(executing, 1, true); - rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); - - _Thread_Enable_dispatch(); - sc = rtems_task_delete(task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } @@ -457,6 +458,9 @@ static void test_case_unblock_op( ) { Thread_Control *needs_help; + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); switch (new_state) { case SCHEDULER_SMP_NODE_SCHEDULED: @@ -489,6 +493,11 @@ static void test_case_unblock_op( rtems_test_assert(0); break; } + + change_priority(executing, 1, true); + rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); + + _Thread_Dispatch_enable( cpu_self ); } static void test_unblock_op(void) @@ -501,10 +510,7 @@ static void test_unblock_op(void) size_t i; task_id = start_task(3); - - _Thread_Disable_dispatch(); - - executing = _Thread_Executing; + executing = _Thread_Get_executing(); executing_node = _Scheduler_SMP_Thread_get_node(executing); other = get_thread_by_id(task_id); @@ -518,11 +524,6 @@ static void test_unblock_op(void) ); } - change_priority(executing, 1, true); - rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED); - - _Thread_Enable_dispatch(); - sc = rtems_task_delete(task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } -- cgit v1.2.3 From 4117cd163977737a5e6633c7117d10aa194304cb Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Thu, 19 Mar 2015 11:38:14 +0100 Subject: timecounter: Import from FreeBSD Update #2271. --- cpukit/score/include/sys/_ffcounter.h | 42 + cpukit/score/include/sys/timeffc.h | 389 +++++++ cpukit/score/include/sys/timepps.h | 249 ++++ cpukit/score/include/sys/timetc.h | 89 ++ cpukit/score/include/sys/timex.h | 171 +++ cpukit/score/src/kern_tc.c | 2039 +++++++++++++++++++++++++++++++++ cpukit/score/src/opt_compat.h | 0 cpukit/score/src/opt_ffclock.h | 0 cpukit/score/src/opt_ntp.h | 0 9 files changed, 2979 insertions(+) create mode 100644 cpukit/score/include/sys/_ffcounter.h create mode 100644 cpukit/score/include/sys/timeffc.h create mode 100644 cpukit/score/include/sys/timepps.h create mode 100644 cpukit/score/include/sys/timetc.h create mode 100644 cpukit/score/include/sys/timex.h create mode 100644 cpukit/score/src/kern_tc.c create mode 100644 cpukit/score/src/opt_compat.h create mode 100644 cpukit/score/src/opt_ffclock.h create mode 100644 cpukit/score/src/opt_ntp.h diff --git a/cpukit/score/include/sys/_ffcounter.h b/cpukit/score/include/sys/_ffcounter.h new file mode 100644 index 0000000000..d83c48cd44 --- /dev/null +++ b/cpukit/score/include/sys/_ffcounter.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2011 The University of Melbourne + * All rights reserved. + * + * This software was developed by Julien Ridoux at the University of Melbourne + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD r277406 2015-01-20T03:54:30Z$ + */ + +#ifndef _SYS__FFCOUNTER_H_ +#define _SYS__FFCOUNTER_H_ + +/* + * The feed-forward clock counter. The fundamental element of a feed-forward + * clock is a wide monotonically increasing counter that accumulates at the same + * rate as the selected timecounter. + */ +typedef uint64_t ffcounter; + +#endif /* _SYS__FFCOUNTER_H_ */ diff --git a/cpukit/score/include/sys/timeffc.h b/cpukit/score/include/sys/timeffc.h new file mode 100644 index 0000000000..893afe8bda --- /dev/null +++ b/cpukit/score/include/sys/timeffc.h @@ -0,0 +1,389 @@ +/*- + * Copyright (c) 2011 The University of Melbourne + * All rights reserved. + * + * This software was developed by Julien Ridoux at the University of Melbourne + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD r277406 2015-01-20T03:54:30Z$ + */ + +#ifndef _SYS_TIMEFF_H_ +#define _SYS_TIMEFF_H_ + +#include + +/* + * Feed-forward clock estimate + * Holds time mark as a ffcounter and conversion to bintime based on current + * timecounter period and offset estimate passed by the synchronization daemon. + * Provides time of last daemon update, clock status and bound on error. + */ +struct ffclock_estimate { + struct bintime update_time; /* Time of last estimates update. */ + ffcounter update_ffcount; /* Counter value at last update. */ + ffcounter leapsec_next; /* Counter value of next leap second. */ + uint64_t period; /* Estimate of counter period. */ + uint32_t errb_abs; /* Bound on absolute clock error [ns]. */ + uint32_t errb_rate; /* Bound on counter rate error [ps/s]. */ + uint32_t status; /* Clock status. */ + int16_t leapsec_total; /* All leap seconds seen so far. */ + int8_t leapsec; /* Next leap second (in {-1,0,1}). */ +}; + +#if __BSD_VISIBLE +#ifdef _KERNEL + +/* Define the kern.sysclock sysctl tree. */ +SYSCTL_DECL(_kern_sysclock); + +/* Define the kern.sysclock.ffclock sysctl tree. */ +SYSCTL_DECL(_kern_sysclock_ffclock); + +/* + * Index into the sysclocks array for obtaining the ASCII name of a particular + * sysclock. + */ +#define SYSCLOCK_FBCK 0 +#define SYSCLOCK_FFWD 1 +extern int sysclock_active; + +/* + * Parameters of counter characterisation required by feed-forward algorithms. + */ +#define FFCLOCK_SKM_SCALE 1024 + +/* + * Feed-forward clock status + */ +#define FFCLOCK_STA_UNSYNC 1 +#define FFCLOCK_STA_WARMUP 2 + +/* + * Flags for use by sysclock_snap2bintime() and various ffclock_ functions to + * control how the timecounter hardware is read and how the hardware snapshot is + * converted into absolute time. + * {FB|FF}CLOCK_FAST: Do not read the hardware counter, instead using the + * value at last tick. The time returned has a resolution + * of the kernel tick timer (1/hz [s]). + * FFCLOCK_LERP: Linear interpolation of ffclock time to guarantee + * monotonic time. + * FFCLOCK_LEAPSEC: Include leap seconds. + * {FB|FF}CLOCK_UPTIME: Time stamp should be relative to system boot, not epoch. + */ +#define FFCLOCK_FAST 0x00000001 +#define FFCLOCK_LERP 0x00000002 +#define FFCLOCK_LEAPSEC 0x00000004 +#define FFCLOCK_UPTIME 0x00000008 +#define FFCLOCK_MASK 0x0000ffff + +#define FBCLOCK_FAST 0x00010000 /* Currently unused. */ +#define FBCLOCK_UPTIME 0x00020000 +#define FBCLOCK_MASK 0xffff0000 + +/* + * Feedback clock specific info structure. The feedback clock's estimation of + * clock error is an absolute figure determined by the NTP algorithm. The status + * is determined by the userland daemon. + */ +struct fbclock_info { + struct bintime error; + struct bintime tick_time; + uint64_t th_scale; + int status; +}; + +/* + * Feed-forward clock specific info structure. The feed-forward clock's + * estimation of clock error is an upper bound, which although potentially + * looser than the feedback clock equivalent, is much more reliable. The status + * is determined by the userland daemon. + */ +struct ffclock_info { + struct bintime error; + struct bintime tick_time; + struct bintime tick_time_lerp; + uint64_t period; + uint64_t period_lerp; + int leapsec_adjustment; + int status; +}; + +/* + * Snapshot of system clocks and related information. Holds time read from each + * clock based on a single read of the active hardware timecounter, as well as + * respective clock information such as error estimates and the ffcounter value + * at the time of the read. + */ +struct sysclock_snap { + struct fbclock_info fb_info; + struct ffclock_info ff_info; + ffcounter ffcount; + unsigned int delta; + int sysclock_active; +}; + +/* Take a snapshot of the system clocks and related information. */ +void sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast); + +/* Convert a timestamp from the selected system clock into bintime. */ +int sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, + int whichclock, uint32_t flags); + +/* Resets feed-forward clock from RTC */ +void ffclock_reset_clock(struct timespec *ts); + +/* + * Return the current value of the feed-forward clock counter. Essential to + * measure time interval in counter units. If a fast timecounter is used by the + * system, may also allow fast but accurate timestamping. + */ +void ffclock_read_counter(ffcounter *ffcount); + +/* + * Retrieve feed-forward counter value and time of last kernel tick. This + * accepts the FFCLOCK_LERP flag. + */ +void ffclock_last_tick(ffcounter *ffcount, struct bintime *bt, uint32_t flags); + +/* + * Low level routines to convert a counter timestamp into absolute time and a + * counter timestamp interval into an interval in seconds. The absolute time + * conversion accepts the FFCLOCK_LERP flag. + */ +void ffclock_convert_abs(ffcounter ffcount, struct bintime *bt, uint32_t flags); +void ffclock_convert_diff(ffcounter ffdelta, struct bintime *bt); + +/* + * Feed-forward clock routines. + * + * These functions rely on the timecounters and ffclock_estimates stored in + * fftimehands. Note that the error_bound parameter is not the error of the + * clock but an upper bound on the error of the absolute time or time interval + * returned. + * + * ffclock_abstime(): retrieves current time as counter value and convert this + * timestamp in seconds. The value (in seconds) of the converted timestamp + * depends on the flags passed: for a given counter value, different + * conversions are possible. Different clock models can be selected by + * combining flags (for example (FFCLOCK_LERP|FFCLOCK_UPTIME) produces + * linearly interpolated uptime). + * ffclock_difftime(): computes a time interval in seconds based on an interval + * measured in ffcounter units. This should be the preferred way to measure + * small time intervals very accurately. + */ +void ffclock_abstime(ffcounter *ffcount, struct bintime *bt, + struct bintime *error_bound, uint32_t flags); +void ffclock_difftime(ffcounter ffdelta, struct bintime *bt, + struct bintime *error_bound); + +/* + * Wrapper routines to return current absolute time using the feed-forward + * clock. These functions are named after those defined in , which + * contains a description of the original ones. + */ +void ffclock_bintime(struct bintime *bt); +void ffclock_nanotime(struct timespec *tsp); +void ffclock_microtime(struct timeval *tvp); + +void ffclock_getbintime(struct bintime *bt); +void ffclock_getnanotime(struct timespec *tsp); +void ffclock_getmicrotime(struct timeval *tvp); + +void ffclock_binuptime(struct bintime *bt); +void ffclock_nanouptime(struct timespec *tsp); +void ffclock_microuptime(struct timeval *tvp); + +void ffclock_getbinuptime(struct bintime *bt); +void ffclock_getnanouptime(struct timespec *tsp); +void ffclock_getmicrouptime(struct timeval *tvp); + +/* + * Wrapper routines to convert a time interval specified in ffcounter units into + * seconds using the current feed-forward clock estimates. + */ +void ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt); +void ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp); +void ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp); + +/* + * When FFCLOCK is enabled in the kernel, [get]{bin,nano,micro}[up]time() become + * wrappers around equivalent feedback or feed-forward functions. Provide access + * outside of kern_tc.c to the feedback clock equivalent functions for + * specialised use i.e. these are not for general consumption. + */ +void fbclock_bintime(struct bintime *bt); +void fbclock_nanotime(struct timespec *tsp); +void fbclock_microtime(struct timeval *tvp); + +void fbclock_getbintime(struct bintime *bt); +void fbclock_getnanotime(struct timespec *tsp); +void fbclock_getmicrotime(struct timeval *tvp); + +void fbclock_binuptime(struct bintime *bt); +void fbclock_nanouptime(struct timespec *tsp); +void fbclock_microuptime(struct timeval *tvp); + +void fbclock_getbinuptime(struct bintime *bt); +void fbclock_getnanouptime(struct timespec *tsp); +void fbclock_getmicrouptime(struct timeval *tvp); + +/* + * Public system clock wrapper API which allows consumers to select which clock + * to obtain time from, independent of the current default system clock. These + * wrappers should be used instead of directly calling the underlying fbclock_ + * or ffclock_ functions. + */ +static inline void +bintime_fromclock(struct bintime *bt, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_bintime(bt); + else + fbclock_bintime(bt); +} + +static inline void +nanotime_fromclock(struct timespec *tsp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_nanotime(tsp); + else + fbclock_nanotime(tsp); +} + +static inline void +microtime_fromclock(struct timeval *tvp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_microtime(tvp); + else + fbclock_microtime(tvp); +} + +static inline void +getbintime_fromclock(struct bintime *bt, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_getbintime(bt); + else + fbclock_getbintime(bt); +} + +static inline void +getnanotime_fromclock(struct timespec *tsp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_getnanotime(tsp); + else + fbclock_getnanotime(tsp); +} + +static inline void +getmicrotime_fromclock(struct timeval *tvp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_getmicrotime(tvp); + else + fbclock_getmicrotime(tvp); +} + +static inline void +binuptime_fromclock(struct bintime *bt, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_binuptime(bt); + else + fbclock_binuptime(bt); +} + +static inline void +nanouptime_fromclock(struct timespec *tsp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_nanouptime(tsp); + else + fbclock_nanouptime(tsp); +} + +static inline void +microuptime_fromclock(struct timeval *tvp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_microuptime(tvp); + else + fbclock_microuptime(tvp); +} + +static inline void +getbinuptime_fromclock(struct bintime *bt, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_getbinuptime(bt); + else + fbclock_getbinuptime(bt); +} + +static inline void +getnanouptime_fromclock(struct timespec *tsp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_getnanouptime(tsp); + else + fbclock_getnanouptime(tsp); +} + +static inline void +getmicrouptime_fromclock(struct timeval *tvp, int whichclock) +{ + + if (whichclock == SYSCLOCK_FFWD) + ffclock_getmicrouptime(tvp); + else + fbclock_getmicrouptime(tvp); +} + +#else /* !_KERNEL */ + +/* Feed-Forward Clock system calls. */ +__BEGIN_DECLS +int ffclock_getcounter(ffcounter *ffcount); +int ffclock_getestimate(struct ffclock_estimate *cest); +int ffclock_setestimate(struct ffclock_estimate *cest); +__END_DECLS + +#endif /* _KERNEL */ +#endif /* __BSD_VISIBLE */ +#endif /* _SYS_TIMEFF_H_ */ diff --git a/cpukit/score/include/sys/timepps.h b/cpukit/score/include/sys/timepps.h new file mode 100644 index 0000000000..71d74f54ee --- /dev/null +++ b/cpukit/score/include/sys/timepps.h @@ -0,0 +1,249 @@ +/*- + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Julien Ridoux at the University + * of Melbourne under sponsorship from the FreeBSD Foundation. + * + * $FreeBSD r277406 2015-01-20T03:54:30Z$ + * + * The is a FreeBSD version of the RFC 2783 API for Pulse Per Second + * timing interfaces. + */ + +#ifndef _SYS_TIMEPPS_H_ +#define _SYS_TIMEPPS_H_ + +#include +#include +#include + +#define PPS_API_VERS_1 1 + +typedef int pps_handle_t; + +typedef unsigned pps_seq_t; + +typedef struct ntp_fp { + unsigned int integral; + unsigned int fractional; +} ntp_fp_t; + +typedef union pps_timeu { + struct timespec tspec; + ntp_fp_t ntpfp; + unsigned long longpad[3]; +} pps_timeu_t; + +typedef struct { + pps_seq_t assert_sequence; /* assert event seq # */ + pps_seq_t clear_sequence; /* clear event seq # */ + pps_timeu_t assert_tu; + pps_timeu_t clear_tu; + int current_mode; /* current mode bits */ +} pps_info_t; + +typedef struct { + pps_seq_t assert_sequence; /* assert event seq # */ + pps_seq_t clear_sequence; /* clear event seq # */ + pps_timeu_t assert_tu; + pps_timeu_t clear_tu; + ffcounter assert_ffcount; /* ffcounter on assert event */ + ffcounter clear_ffcount; /* ffcounter on clear event */ + int current_mode; /* current mode bits */ +} pps_info_ffc_t; + +#define assert_timestamp assert_tu.tspec +#define clear_timestamp clear_tu.tspec + +#define assert_timestamp_ntpfp assert_tu.ntpfp +#define clear_timestamp_ntpfp clear_tu.ntpfp + +typedef struct { + int api_version; /* API version # */ + int mode; /* mode bits */ + pps_timeu_t assert_off_tu; + pps_timeu_t clear_off_tu; +} pps_params_t; + +#define assert_offset assert_off_tu.tspec +#define clear_offset clear_off_tu.tspec + +#define assert_offset_ntpfp assert_off_tu.ntpfp +#define clear_offset_ntpfp clear_off_tu.ntpfp + + +#define PPS_CAPTUREASSERT 0x01 +#define PPS_CAPTURECLEAR 0x02 +#define PPS_CAPTUREBOTH 0x03 + +#define PPS_OFFSETASSERT 0x10 +#define PPS_OFFSETCLEAR 0x20 + +#define PPS_ECHOASSERT 0x40 +#define PPS_ECHOCLEAR 0x80 + +#define PPS_CANWAIT 0x100 +#define PPS_CANPOLL 0x200 + +#define PPS_TSFMT_TSPEC 0x1000 +#define PPS_TSFMT_NTPFP 0x2000 + +#define PPS_TSCLK_FBCK 0x10000 +#define PPS_TSCLK_FFWD 0x20000 +#define PPS_TSCLK_MASK 0x30000 + +#define PPS_KC_HARDPPS 0 +#define PPS_KC_HARDPPS_PLL 1 +#define PPS_KC_HARDPPS_FLL 2 + +struct pps_fetch_args { + int tsformat; + pps_info_t pps_info_buf; + struct timespec timeout; +}; + +struct pps_fetch_ffc_args { + int tsformat; + pps_info_ffc_t pps_info_buf_ffc; + struct timespec timeout; +}; + +struct pps_kcbind_args { + int kernel_consumer; + int edge; + int tsformat; +}; + +#define PPS_IOC_CREATE _IO('1', 1) +#define PPS_IOC_DESTROY _IO('1', 2) +#define PPS_IOC_SETPARAMS _IOW('1', 3, pps_params_t) +#define PPS_IOC_GETPARAMS _IOR('1', 4, pps_params_t) +#define PPS_IOC_GETCAP _IOR('1', 5, int) +#define PPS_IOC_FETCH _IOWR('1', 6, struct pps_fetch_args) +#define PPS_IOC_KCBIND _IOW('1', 7, struct pps_kcbind_args) +#define PPS_IOC_FETCH_FFCOUNTER _IOWR('1', 8, struct pps_fetch_ffc_args) + +#ifdef _KERNEL + +struct pps_state { + /* Capture information. */ + struct timehands *capth; + struct fftimehands *capffth; + unsigned capgen; + unsigned capcount; + + /* State information. */ + pps_params_t ppsparam; + pps_info_t ppsinfo; + pps_info_ffc_t ppsinfo_ffc; + int kcmode; + int ppscap; + struct timecounter *ppstc; + unsigned ppscount[3]; +}; + +void pps_capture(struct pps_state *pps); +void pps_event(struct pps_state *pps, int event); +void pps_init(struct pps_state *pps); +int pps_ioctl(unsigned long cmd, caddr_t data, struct pps_state *pps); +void hardpps(struct timespec *tsp, long nsec); + +#else /* !_KERNEL */ + +static __inline int +time_pps_create(int filedes, pps_handle_t *handle) +{ + int error; + + *handle = -1; + error = ioctl(filedes, PPS_IOC_CREATE, 0); + if (error < 0) + return (-1); + *handle = filedes; + return (0); +} + +static __inline int +time_pps_destroy(pps_handle_t handle) +{ + return (ioctl(handle, PPS_IOC_DESTROY, 0)); +} + +static __inline int +time_pps_setparams(pps_handle_t handle, const pps_params_t *ppsparams) +{ + return (ioctl(handle, PPS_IOC_SETPARAMS, ppsparams)); +} + +static __inline int +time_pps_getparams(pps_handle_t handle, pps_params_t *ppsparams) +{ + return (ioctl(handle, PPS_IOC_GETPARAMS, ppsparams)); +} + +static __inline int +time_pps_getcap(pps_handle_t handle, int *mode) +{ + return (ioctl(handle, PPS_IOC_GETCAP, mode)); +} + +static __inline int +time_pps_fetch(pps_handle_t handle, const int tsformat, + pps_info_t *ppsinfobuf, const struct timespec *timeout) +{ + int error; + struct pps_fetch_args arg; + + arg.tsformat = tsformat; + if (timeout == NULL) { + arg.timeout.tv_sec = -1; + arg.timeout.tv_nsec = -1; + } else + arg.timeout = *timeout; + error = ioctl(handle, PPS_IOC_FETCH, &arg); + *ppsinfobuf = arg.pps_info_buf; + return (error); +} + +static __inline int +time_pps_fetch_ffc(pps_handle_t handle, const int tsformat, + pps_info_ffc_t *ppsinfobuf, const struct timespec *timeout) +{ + struct pps_fetch_ffc_args arg; + int error; + + arg.tsformat = tsformat; + if (timeout == NULL) { + arg.timeout.tv_sec = -1; + arg.timeout.tv_nsec = -1; + } else { + arg.timeout = *timeout; + } + error = ioctl(handle, PPS_IOC_FETCH_FFCOUNTER, &arg); + *ppsinfobuf = arg.pps_info_buf_ffc; + return (error); +} + +static __inline int +time_pps_kcbind(pps_handle_t handle, const int kernel_consumer, + const int edge, const int tsformat) +{ + struct pps_kcbind_args arg; + + arg.kernel_consumer = kernel_consumer; + arg.edge = edge; + arg.tsformat = tsformat; + return (ioctl(handle, PPS_IOC_KCBIND, &arg)); +} + +#endif /* KERNEL */ + +#endif /* !_SYS_TIMEPPS_H_ */ diff --git a/cpukit/score/include/sys/timetc.h b/cpukit/score/include/sys/timetc.h new file mode 100644 index 0000000000..f553101b71 --- /dev/null +++ b/cpukit/score/include/sys/timetc.h @@ -0,0 +1,89 @@ +/*- + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $FreeBSD r277406 2015-01-20T03:54:30Z$ + */ + +#ifndef _SYS_TIMETC_H_ +#define _SYS_TIMETC_H_ + +#ifndef _KERNEL +#error "no user-serviceable parts inside" +#endif + +/*- + * `struct timecounter' is the interface between the hardware which implements + * a timecounter and the MI code which uses this to keep track of time. + * + * A timecounter is a binary counter which has two properties: + * * it runs at a fixed, known frequency. + * * it has sufficient bits to not roll over in less than approximately + * max(2 msec, 2/HZ seconds). (The value 2 here is really 1 + delta, + * for some indeterminate value of delta.) + */ + +struct timecounter; +typedef u_int timecounter_get_t(struct timecounter *); +typedef void timecounter_pps_t(struct timecounter *); + +struct timecounter { + timecounter_get_t *tc_get_timecount; + /* + * This function reads the counter. It is not required to + * mask any unimplemented bits out, as long as they are + * constant. + */ + timecounter_pps_t *tc_poll_pps; + /* + * This function is optional. It will be called whenever the + * timecounter is rewound, and is intended to check for PPS + * events. Normal hardware does not need it but timecounters + * which latch PPS in hardware (like sys/pci/xrpu.c) do. + */ + u_int tc_counter_mask; + /* This mask should mask off any unimplemented bits. */ + uint64_t tc_frequency; + /* Frequency of the counter in Hz. */ + char *tc_name; + /* Name of the timecounter. */ + int tc_quality; + /* + * Used to determine if this timecounter is better than + * another timecounter higher means better. Negative + * means "only use at explicit request". + */ + u_int tc_flags; +#define TC_FLAGS_C2STOP 1 /* Timer dies in C2+. */ +#define TC_FLAGS_SUSPEND_SAFE 2 /* + * Timer functional across + * suspend/resume. + */ + + void *tc_priv; + /* Pointer to the timecounter's private parts. */ + struct timecounter *tc_next; + /* Pointer to the next timecounter. */ +}; + +extern struct timecounter *timecounter; +extern int tc_min_ticktock_freq; /* + * Minimal tc_ticktock() call frequency, + * required to handle counter wraps. + */ + +u_int64_t tc_getfrequency(void); +void tc_init(struct timecounter *tc); +void tc_setclock(struct timespec *ts); +void tc_ticktock(int cnt); +void cpu_tick_calibration(void); + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_kern_timecounter); +#endif + +#endif /* !_SYS_TIMETC_H_ */ diff --git a/cpukit/score/include/sys/timex.h b/cpukit/score/include/sys/timex.h new file mode 100644 index 0000000000..9eb0efb379 --- /dev/null +++ b/cpukit/score/include/sys/timex.h @@ -0,0 +1,171 @@ +/*- + *********************************************************************** + * * + * Copyright (c) David L. Mills 1993-2001 * + * Copyright (c) Poul-Henning Kamp 2000-2001 * + * * + * Permission to use, copy, modify, and distribute this software and * + * its documentation for any purpose and without fee is hereby * + * granted, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission * + * notice appear in supporting documentation, and that the name * + * University of Delaware not be used in advertising or publicity * + * pertaining to distribution of the software without specific, * + * written prior permission. The University of Delaware makes no * + * representations about the suitability this software for any * + * purpose. It is provided "as is" without express or implied * + * warranty. * + * * + *********************************************************************** + * + * $FreeBSD r277406 2015-01-20T03:54:30Z$ + * + * This header file defines the Network Time Protocol (NTP) interfaces + * for user and daemon application programs. + * + * This file was originally created 17 Sep 93 by David L. Mills, Professor + * of University of Delaware, building on work which had already been ongoing + * for a decade and a half at that point in time. + * + * In 2000 the APIs got a upgrade from microseconds to nanoseconds, + * a joint work between Poul-Henning Kamp and David L. Mills. + * + */ + +#ifndef _SYS_TIMEX_H_ +#define _SYS_TIMEX_H_ 1 + +#define NTP_API 4 /* NTP API version */ + +#ifdef __FreeBSD__ +#include +#endif /* __FreeBSD__ */ + +/* + * The following defines establish the performance envelope of the + * kernel discipline loop. Phase or frequency errors greater than + * NAXPHASE or MAXFREQ are clamped to these maxima. For update intervals + * less than MINSEC, the loop always operates in PLL mode; while, for + * update intervals greater than MAXSEC, the loop always operates in FLL + * mode. Between these two limits the operating mode is selected by the + * STA_FLL bit in the status word. + */ + +#define MAXPHASE 500000000L /* max phase error (ns) */ +#define MAXFREQ 500000L /* max freq error (ns/s) */ +#define MINSEC 256 /* min FLL update interval (s) */ +#define MAXSEC 2048 /* max PLL update interval (s) */ +#define NANOSECOND 1000000000L /* nanoseconds in one second */ +#define SCALE_PPM (65536 / 1000) /* crude ns/s to scaled PPM */ +#define MAXTC 10 /* max time constant */ + +/* + * Control mode codes (timex.modes) + */ +#define MOD_OFFSET 0x0001 /* set time offset */ +#define MOD_FREQUENCY 0x0002 /* set frequency offset */ +#define MOD_MAXERROR 0x0004 /* set maximum time error */ +#define MOD_ESTERROR 0x0008 /* set estimated time error */ +#define MOD_STATUS 0x0010 /* set clock status bits */ +#define MOD_TIMECONST 0x0020 /* set PLL time constant */ +#define MOD_PPSMAX 0x0040 /* set PPS maximum averaging time */ +#define MOD_TAI 0x0080 /* set TAI offset */ +#define MOD_MICRO 0x1000 /* select microsecond resolution */ +#define MOD_NANO 0x2000 /* select nanosecond resolution */ +#define MOD_CLKB 0x4000 /* select clock B */ +#define MOD_CLKA 0x8000 /* select clock A */ + +/* + * Status codes (timex.status) + */ +#define STA_PLL 0x0001 /* enable PLL updates (rw) */ +#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */ +#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */ +#define STA_FLL 0x0008 /* enable FLL mode (rw) */ +#define STA_INS 0x0010 /* insert leap (rw) */ +#define STA_DEL 0x0020 /* delete leap (rw) */ +#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */ +#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */ +#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */ +#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */ +#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */ +#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */ +#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */ +#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */ +#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */ +#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */ + +#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ + STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK) + +/* + * Clock states (ntptimeval.time_state) + */ +#define TIME_OK 0 /* no leap second warning */ +#define TIME_INS 1 /* insert leap second warning */ +#define TIME_DEL 2 /* delete leap second warning */ +#define TIME_OOP 3 /* leap second in progress */ +#define TIME_WAIT 4 /* leap second has occured */ +#define TIME_ERROR 5 /* error (see status word) */ + +/* + * NTP user interface -- ntp_gettime(2) - used to read kernel clock values + */ +struct ntptimeval { + struct timespec time; /* current time (ns) (ro) */ + long maxerror; /* maximum error (us) (ro) */ + long esterror; /* estimated error (us) (ro) */ + long tai; /* TAI offset */ + int time_state; /* time status */ +}; + +/* + * NTP daemon interface -- ntp_adjtime(2) -- used to discipline CPU clock + * oscillator and control/determine status. + * + * Note: The offset, precision and jitter members are in microseconds if + * STA_NANO is zero and nanoseconds if not. + */ +struct timex { + unsigned int modes; /* clock mode bits (wo) */ + long offset; /* time offset (ns/us) (rw) */ + long freq; /* frequency offset (scaled PPM) (rw) */ + long maxerror; /* maximum error (us) (rw) */ + long esterror; /* estimated error (us) (rw) */ + int status; /* clock status bits (rw) */ + long constant; /* poll interval (log2 s) (rw) */ + long precision; /* clock precision (ns/us) (ro) */ + long tolerance; /* clock frequency tolerance (scaled + * PPM) (ro) */ + /* + * The following read-only structure members are implemented + * only if the PPS signal discipline is configured in the + * kernel. They are included in all configurations to insure + * portability. + */ + long ppsfreq; /* PPS frequency (scaled PPM) (ro) */ + long jitter; /* PPS jitter (ns/us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long stabil; /* PPS stability (scaled PPM) (ro) */ + long jitcnt; /* jitter limit exceeded (ro) */ + long calcnt; /* calibration intervals (ro) */ + long errcnt; /* calibration errors (ro) */ + long stbcnt; /* stability limit exceeded (ro) */ +}; + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +void ntp_update_second(int64_t *adjustment, time_t *newsec); +#else /* !_KERNEL */ +#include + +__BEGIN_DECLS +int ntp_adjtime(struct timex *); +int ntp_gettime(struct ntptimeval *); +__END_DECLS +#endif /* _KERNEL */ + +#endif /* __FreeBSD__ */ + +#endif /* !_SYS_TIMEX_H_ */ diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c new file mode 100644 index 0000000000..82e5e1e50c --- /dev/null +++ b/cpukit/score/src/kern_tc.c @@ -0,0 +1,2039 @@ +/*- + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Julien Ridoux at the University + * of Melbourne under sponsorship from the FreeBSD Foundation. + */ + +#include +__FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); + +#include "opt_compat.h" +#include "opt_ntp.h" +#include "opt_ffclock.h" + +#include +#include +#include +#ifdef FFCLOCK +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * A large step happens on boot. This constant detects such steps. + * It is relatively small so that ntp_update_second gets called enough + * in the typical 'missed a couple of seconds' case, but doesn't loop + * forever when the time step is large. + */ +#define LARGE_STEP 200 + +/* + * Implement a dummy timecounter which we can use until we get a real one + * in the air. This allows the console and other early stuff to use + * time services. + */ + +static u_int +dummy_get_timecount(struct timecounter *tc) +{ + static u_int now; + + return (++now); +} + +static struct timecounter dummy_timecounter = { + dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000 +}; + +struct timehands { + /* These fields must be initialized by the driver. */ + struct timecounter *th_counter; + int64_t th_adjustment; + uint64_t th_scale; + u_int th_offset_count; + struct bintime th_offset; + struct timeval th_microtime; + struct timespec th_nanotime; + /* Fields not to be copied in tc_windup start with th_generation. */ + volatile u_int th_generation; + struct timehands *th_next; +}; + +static struct timehands th0; +static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; +static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; +static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8}; +static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7}; +static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6}; +static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; +static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; +static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; +static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; +static struct timehands th0 = { + &dummy_timecounter, + 0, + (uint64_t)-1 / 1000000, + 0, + {1, 0}, + {0, 0}, + {0, 0}, + 1, + &th1 +}; + +static struct timehands *volatile timehands = &th0; +struct timecounter *timecounter = &dummy_timecounter; +static struct timecounter *timecounters = &dummy_timecounter; + +int tc_min_ticktock_freq = 1; + +volatile time_t time_second = 1; +volatile time_t time_uptime = 1; + +struct bintime boottimebin; +struct timeval boottime; +static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD, + NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime"); + +SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); +static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc, CTLFLAG_RW, 0, ""); + +static int timestepwarnings; +SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RW, + ×tepwarnings, 0, "Log time steps"); + +struct bintime bt_timethreshold; +struct bintime bt_tickthreshold; +sbintime_t sbt_timethreshold; +sbintime_t sbt_tickthreshold; +struct bintime tc_tick_bt; +sbintime_t tc_tick_sbt; +int tc_precexp; +int tc_timepercentage = TC_DEFAULTPERC; +static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation, + CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, + sysctl_kern_timecounter_adjprecision, "I", + "Allowed time interval deviation in percents"); + +static void tc_windup(void); +static void cpu_tick_calibrate(int); + +void dtrace_getnanotime(struct timespec *tsp); + +static int +sysctl_kern_boottime(SYSCTL_HANDLER_ARGS) +{ +#ifndef __mips__ +#ifdef SCTL_MASK32 + int tv[2]; + + if (req->flags & SCTL_MASK32) { + tv[0] = boottime.tv_sec; + tv[1] = boottime.tv_usec; + return SYSCTL_OUT(req, tv, sizeof(tv)); + } else +#endif +#endif + return SYSCTL_OUT(req, &boottime, sizeof(boottime)); +} + +static int +sysctl_kern_timecounter_get(SYSCTL_HANDLER_ARGS) +{ + u_int ncount; + struct timecounter *tc = arg1; + + ncount = tc->tc_get_timecount(tc); + return sysctl_handle_int(oidp, &ncount, 0, req); +} + +static int +sysctl_kern_timecounter_freq(SYSCTL_HANDLER_ARGS) +{ + uint64_t freq; + struct timecounter *tc = arg1; + + freq = tc->tc_frequency; + return sysctl_handle_64(oidp, &freq, 0, req); +} + +/* + * Return the difference between the timehands' counter value now and what + * was when we copied it to the timehands' offset_count. + */ +static __inline u_int +tc_delta(struct timehands *th) +{ + struct timecounter *tc; + + tc = th->th_counter; + return ((tc->tc_get_timecount(tc) - th->th_offset_count) & + tc->tc_counter_mask); +} + +/* + * Functions for reading the time. We have to loop until we are sure that + * the timehands that we operated on was not updated under our feet. See + * the comment in for a description of these 12 functions. + */ + +#ifdef FFCLOCK +void +fbclock_binuptime(struct bintime *bt) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + *bt = th->th_offset; + bintime_addx(bt, th->th_scale * tc_delta(th)); + } while (gen == 0 || gen != th->th_generation); +} + +void +fbclock_nanouptime(struct timespec *tsp) +{ + struct bintime bt; + + fbclock_binuptime(&bt); + bintime2timespec(&bt, tsp); +} + +void +fbclock_microuptime(struct timeval *tvp) +{ + struct bintime bt; + + fbclock_binuptime(&bt); + bintime2timeval(&bt, tvp); +} + +void +fbclock_bintime(struct bintime *bt) +{ + + fbclock_binuptime(bt); + bintime_add(bt, &boottimebin); +} + +void +fbclock_nanotime(struct timespec *tsp) +{ + struct bintime bt; + + fbclock_bintime(&bt); + bintime2timespec(&bt, tsp); +} + +void +fbclock_microtime(struct timeval *tvp) +{ + struct bintime bt; + + fbclock_bintime(&bt); + bintime2timeval(&bt, tvp); +} + +void +fbclock_getbinuptime(struct bintime *bt) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + *bt = th->th_offset; + } while (gen == 0 || gen != th->th_generation); +} + +void +fbclock_getnanouptime(struct timespec *tsp) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + bintime2timespec(&th->th_offset, tsp); + } while (gen == 0 || gen != th->th_generation); +} + +void +fbclock_getmicrouptime(struct timeval *tvp) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + bintime2timeval(&th->th_offset, tvp); + } while (gen == 0 || gen != th->th_generation); +} + +void +fbclock_getbintime(struct bintime *bt) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + *bt = th->th_offset; + } while (gen == 0 || gen != th->th_generation); + bintime_add(bt, &boottimebin); +} + +void +fbclock_getnanotime(struct timespec *tsp) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + *tsp = th->th_nanotime; + } while (gen == 0 || gen != th->th_generation); +} + +void +fbclock_getmicrotime(struct timeval *tvp) +{ + struct timehands *th; + unsigned int gen; + + do { + th = timehands; + gen = th->th_generation; + *tvp = th->th_microtime; + } while (gen == 0 || gen != th->th_generation); +} +#else /* !FFCLOCK */ +void +binuptime(struct bintime *bt) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + *bt = th->th_offset; + bintime_addx(bt, th->th_scale * tc_delta(th)); + } while (gen == 0 || gen != th->th_generation); +} + +void +nanouptime(struct timespec *tsp) +{ + struct bintime bt; + + binuptime(&bt); + bintime2timespec(&bt, tsp); +} + +void +microuptime(struct timeval *tvp) +{ + struct bintime bt; + + binuptime(&bt); + bintime2timeval(&bt, tvp); +} + +void +bintime(struct bintime *bt) +{ + + binuptime(bt); + bintime_add(bt, &boottimebin); +} + +void +nanotime(struct timespec *tsp) +{ + struct bintime bt; + + bintime(&bt); + bintime2timespec(&bt, tsp); +} + +void +microtime(struct timeval *tvp) +{ + struct bintime bt; + + bintime(&bt); + bintime2timeval(&bt, tvp); +} + +void +getbinuptime(struct bintime *bt) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + *bt = th->th_offset; + } while (gen == 0 || gen != th->th_generation); +} + +void +getnanouptime(struct timespec *tsp) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + bintime2timespec(&th->th_offset, tsp); + } while (gen == 0 || gen != th->th_generation); +} + +void +getmicrouptime(struct timeval *tvp) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + bintime2timeval(&th->th_offset, tvp); + } while (gen == 0 || gen != th->th_generation); +} + +void +getbintime(struct bintime *bt) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + *bt = th->th_offset; + } while (gen == 0 || gen != th->th_generation); + bintime_add(bt, &boottimebin); +} + +void +getnanotime(struct timespec *tsp) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + *tsp = th->th_nanotime; + } while (gen == 0 || gen != th->th_generation); +} + +void +getmicrotime(struct timeval *tvp) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + *tvp = th->th_microtime; + } while (gen == 0 || gen != th->th_generation); +} +#endif /* FFCLOCK */ + +#ifdef FFCLOCK +/* + * Support for feed-forward synchronization algorithms. This is heavily inspired + * by the timehands mechanism but kept independent from it. *_windup() functions + * have some connection to avoid accessing the timecounter hardware more than + * necessary. + */ + +/* Feed-forward clock estimates kept updated by the synchronization daemon. */ +struct ffclock_estimate ffclock_estimate; +struct bintime ffclock_boottime; /* Feed-forward boot time estimate. */ +uint32_t ffclock_status; /* Feed-forward clock status. */ +int8_t ffclock_updated; /* New estimates are available. */ +struct mtx ffclock_mtx; /* Mutex on ffclock_estimate. */ + +struct fftimehands { + struct ffclock_estimate cest; + struct bintime tick_time; + struct bintime tick_time_lerp; + ffcounter tick_ffcount; + uint64_t period_lerp; + volatile uint8_t gen; + struct fftimehands *next; +}; + +#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) + +static struct fftimehands ffth[10]; +static struct fftimehands *volatile fftimehands = ffth; + +static void +ffclock_init(void) +{ + struct fftimehands *cur; + struct fftimehands *last; + + memset(ffth, 0, sizeof(ffth)); + + last = ffth + NUM_ELEMENTS(ffth) - 1; + for (cur = ffth; cur < last; cur++) + cur->next = cur + 1; + last->next = ffth; + + ffclock_updated = 0; + ffclock_status = FFCLOCK_STA_UNSYNC; + mtx_init(&ffclock_mtx, "ffclock lock", NULL, MTX_DEF); +} + +/* + * Reset the feed-forward clock estimates. Called from inittodr() to get things + * kick started and uses the timecounter nominal frequency as a first period + * estimate. Note: this function may be called several time just after boot. + * Note: this is the only function that sets the value of boot time for the + * monotonic (i.e. uptime) version of the feed-forward clock. + */ +void +ffclock_reset_clock(struct timespec *ts) +{ + struct timecounter *tc; + struct ffclock_estimate cest; + + tc = timehands->th_counter; + memset(&cest, 0, sizeof(struct ffclock_estimate)); + + timespec2bintime(ts, &ffclock_boottime); + timespec2bintime(ts, &(cest.update_time)); + ffclock_read_counter(&cest.update_ffcount); + cest.leapsec_next = 0; + cest.period = ((1ULL << 63) / tc->tc_frequency) << 1; + cest.errb_abs = 0; + cest.errb_rate = 0; + cest.status = FFCLOCK_STA_UNSYNC; + cest.leapsec_total = 0; + cest.leapsec = 0; + + mtx_lock(&ffclock_mtx); + bcopy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); + ffclock_updated = INT8_MAX; + mtx_unlock(&ffclock_mtx); + + printf("ffclock reset: %s (%llu Hz), time = %ld.%09lu\n", tc->tc_name, + (unsigned long long)tc->tc_frequency, (long)ts->tv_sec, + (unsigned long)ts->tv_nsec); +} + +/* + * Sub-routine to convert a time interval measured in RAW counter units to time + * in seconds stored in bintime format. + * NOTE: bintime_mul requires u_int, but the value of the ffcounter may be + * larger than the max value of u_int (on 32 bit architecture). Loop to consume + * extra cycles. + */ +static void +ffclock_convert_delta(ffcounter ffdelta, uint64_t period, struct bintime *bt) +{ + struct bintime bt2; + ffcounter delta, delta_max; + + delta_max = (1ULL << (8 * sizeof(unsigned int))) - 1; + bintime_clear(bt); + do { + if (ffdelta > delta_max) + delta = delta_max; + else + delta = ffdelta; + bt2.sec = 0; + bt2.frac = period; + bintime_mul(&bt2, (unsigned int)delta); + bintime_add(bt, &bt2); + ffdelta -= delta; + } while (ffdelta > 0); +} + +/* + * Update the fftimehands. + * Push the tick ffcount and time(s) forward based on current clock estimate. + * The conversion from ffcounter to bintime relies on the difference clock + * principle, whose accuracy relies on computing small time intervals. If a new + * clock estimate has been passed by the synchronisation daemon, make it + * current, and compute the linear interpolation for monotonic time if needed. + */ +static void +ffclock_windup(unsigned int delta) +{ + struct ffclock_estimate *cest; + struct fftimehands *ffth; + struct bintime bt, gap_lerp; + ffcounter ffdelta; + uint64_t frac; + unsigned int polling; + uint8_t forward_jump, ogen; + + /* + * Pick the next timehand, copy current ffclock estimates and move tick + * times and counter forward. + */ + forward_jump = 0; + ffth = fftimehands->next; + ogen = ffth->gen; + ffth->gen = 0; + cest = &ffth->cest; + bcopy(&fftimehands->cest, cest, sizeof(struct ffclock_estimate)); + ffdelta = (ffcounter)delta; + ffth->period_lerp = fftimehands->period_lerp; + + ffth->tick_time = fftimehands->tick_time; + ffclock_convert_delta(ffdelta, cest->period, &bt); + bintime_add(&ffth->tick_time, &bt); + + ffth->tick_time_lerp = fftimehands->tick_time_lerp; + ffclock_convert_delta(ffdelta, ffth->period_lerp, &bt); + bintime_add(&ffth->tick_time_lerp, &bt); + + ffth->tick_ffcount = fftimehands->tick_ffcount + ffdelta; + + /* + * Assess the status of the clock, if the last update is too old, it is + * likely the synchronisation daemon is dead and the clock is free + * running. + */ + if (ffclock_updated == 0) { + ffdelta = ffth->tick_ffcount - cest->update_ffcount; + ffclock_convert_delta(ffdelta, cest->period, &bt); + if (bt.sec > 2 * FFCLOCK_SKM_SCALE) + ffclock_status |= FFCLOCK_STA_UNSYNC; + } + + /* + * If available, grab updated clock estimates and make them current. + * Recompute time at this tick using the updated estimates. The clock + * estimates passed the feed-forward synchronisation daemon may result + * in time conversion that is not monotonically increasing (just after + * the update). time_lerp is a particular linear interpolation over the + * synchronisation algo polling period that ensures monotonicity for the + * clock ids requesting it. + */ + if (ffclock_updated > 0) { + bcopy(&ffclock_estimate, cest, sizeof(struct ffclock_estimate)); + ffdelta = ffth->tick_ffcount - cest->update_ffcount; + ffth->tick_time = cest->update_time; + ffclock_convert_delta(ffdelta, cest->period, &bt); + bintime_add(&ffth->tick_time, &bt); + + /* ffclock_reset sets ffclock_updated to INT8_MAX */ + if (ffclock_updated == INT8_MAX) + ffth->tick_time_lerp = ffth->tick_time; + + if (bintime_cmp(&ffth->tick_time, &ffth->tick_time_lerp, >)) + forward_jump = 1; + else + forward_jump = 0; + + bintime_clear(&gap_lerp); + if (forward_jump) { + gap_lerp = ffth->tick_time; + bintime_sub(&gap_lerp, &ffth->tick_time_lerp); + } else { + gap_lerp = ffth->tick_time_lerp; + bintime_sub(&gap_lerp, &ffth->tick_time); + } + + /* + * The reset from the RTC clock may be far from accurate, and + * reducing the gap between real time and interpolated time + * could take a very long time if the interpolated clock insists + * on strict monotonicity. The clock is reset under very strict + * conditions (kernel time is known to be wrong and + * synchronization daemon has been restarted recently. + * ffclock_boottime absorbs the jump to ensure boot time is + * correct and uptime functions stay consistent. + */ + if (((ffclock_status & FFCLOCK_STA_UNSYNC) == FFCLOCK_STA_UNSYNC) && + ((cest->status & FFCLOCK_STA_UNSYNC) == 0) && + ((cest->status & FFCLOCK_STA_WARMUP) == FFCLOCK_STA_WARMUP)) { + if (forward_jump) + bintime_add(&ffclock_boottime, &gap_lerp); + else + bintime_sub(&ffclock_boottime, &gap_lerp); + ffth->tick_time_lerp = ffth->tick_time; + bintime_clear(&gap_lerp); + } + + ffclock_status = cest->status; + ffth->period_lerp = cest->period; + + /* + * Compute corrected period used for the linear interpolation of + * time. The rate of linear interpolation is capped to 5000PPM + * (5ms/s). + */ + if (bintime_isset(&gap_lerp)) { + ffdelta = cest->update_ffcount; + ffdelta -= fftimehands->cest.update_ffcount; + ffclock_convert_delta(ffdelta, cest->period, &bt); + polling = bt.sec; + bt.sec = 0; + bt.frac = 5000000 * (uint64_t)18446744073LL; + bintime_mul(&bt, polling); + if (bintime_cmp(&gap_lerp, &bt, >)) + gap_lerp = bt; + + /* Approximate 1 sec by 1-(1/2^64) to ease arithmetic */ + frac = 0; + if (gap_lerp.sec > 0) { + frac -= 1; + frac /= ffdelta / gap_lerp.sec; + } + frac += gap_lerp.frac / ffdelta; + + if (forward_jump) + ffth->period_lerp += frac; + else + ffth->period_lerp -= frac; + } + + ffclock_updated = 0; + } + if (++ogen == 0) + ogen = 1; + ffth->gen = ogen; + fftimehands = ffth; +} + +/* + * Adjust the fftimehands when the timecounter is changed. Stating the obvious, + * the old and new hardware counter cannot be read simultaneously. tc_windup() + * does read the two counters 'back to back', but a few cycles are effectively + * lost, and not accumulated in tick_ffcount. This is a fairly radical + * operation for a feed-forward synchronization daemon, and it is its job to not + * pushing irrelevant data to the kernel. Because there is no locking here, + * simply force to ignore pending or next update to give daemon a chance to + * realize the counter has changed. + */ +static void +ffclock_change_tc(struct timehands *th) +{ + struct fftimehands *ffth; + struct ffclock_estimate *cest; + struct timecounter *tc; + uint8_t ogen; + + tc = th->th_counter; + ffth = fftimehands->next; + ogen = ffth->gen; + ffth->gen = 0; + + cest = &ffth->cest; + bcopy(&(fftimehands->cest), cest, sizeof(struct ffclock_estimate)); + cest->period = ((1ULL << 63) / tc->tc_frequency ) << 1; + cest->errb_abs = 0; + cest->errb_rate = 0; + cest->status |= FFCLOCK_STA_UNSYNC; + + ffth->tick_ffcount = fftimehands->tick_ffcount; + ffth->tick_time_lerp = fftimehands->tick_time_lerp; + ffth->tick_time = fftimehands->tick_time; + ffth->period_lerp = cest->period; + + /* Do not lock but ignore next update from synchronization daemon. */ + ffclock_updated--; + + if (++ogen == 0) + ogen = 1; + ffth->gen = ogen; + fftimehands = ffth; +} + +/* + * Retrieve feed-forward counter and time of last kernel tick. + */ +void +ffclock_last_tick(ffcounter *ffcount, struct bintime *bt, uint32_t flags) +{ + struct fftimehands *ffth; + uint8_t gen; + + /* + * No locking but check generation has not changed. Also need to make + * sure ffdelta is positive, i.e. ffcount > tick_ffcount. + */ + do { + ffth = fftimehands; + gen = ffth->gen; + if ((flags & FFCLOCK_LERP) == FFCLOCK_LERP) + *bt = ffth->tick_time_lerp; + else + *bt = ffth->tick_time; + *ffcount = ffth->tick_ffcount; + } while (gen == 0 || gen != ffth->gen); +} + +/* + * Absolute clock conversion. Low level function to convert ffcounter to + * bintime. The ffcounter is converted using the current ffclock period estimate + * or the "interpolated period" to ensure monotonicity. + * NOTE: this conversion may have been deferred, and the clock updated since the + * hardware counter has been read. + */ +void +ffclock_convert_abs(ffcounter ffcount, struct bintime *bt, uint32_t flags) +{ + struct fftimehands *ffth; + struct bintime bt2; + ffcounter ffdelta; + uint8_t gen; + + /* + * No locking but check generation has not changed. Also need to make + * sure ffdelta is positive, i.e. ffcount > tick_ffcount. + */ + do { + ffth = fftimehands; + gen = ffth->gen; + if (ffcount > ffth->tick_ffcount) + ffdelta = ffcount - ffth->tick_ffcount; + else + ffdelta = ffth->tick_ffcount - ffcount; + + if ((flags & FFCLOCK_LERP) == FFCLOCK_LERP) { + *bt = ffth->tick_time_lerp; + ffclock_convert_delta(ffdelta, ffth->period_lerp, &bt2); + } else { + *bt = ffth->tick_time; + ffclock_convert_delta(ffdelta, ffth->cest.period, &bt2); + } + + if (ffcount > ffth->tick_ffcount) + bintime_add(bt, &bt2); + else + bintime_sub(bt, &bt2); + } while (gen == 0 || gen != ffth->gen); +} + +/* + * Difference clock conversion. + * Low level function to Convert a time interval measured in RAW counter units + * into bintime. The difference clock allows measuring small intervals much more + * reliably than the absolute clock. + */ +void +ffclock_convert_diff(ffcounter ffdelta, struct bintime *bt) +{ + struct fftimehands *ffth; + uint8_t gen; + + /* No locking but check generation has not changed. */ + do { + ffth = fftimehands; + gen = ffth->gen; + ffclock_convert_delta(ffdelta, ffth->cest.period, bt); + } while (gen == 0 || gen != ffth->gen); +} + +/* + * Access to current ffcounter value. + */ +void +ffclock_read_counter(ffcounter *ffcount) +{ + struct timehands *th; + struct fftimehands *ffth; + unsigned int gen, delta; + + /* + * ffclock_windup() called from tc_windup(), safe to rely on + * th->th_generation only, for correct delta and ffcounter. + */ + do { + th = timehands; + gen = th->th_generation; + ffth = fftimehands; + delta = tc_delta(th); + *ffcount = ffth->tick_ffcount; + } while (gen == 0 || gen != th->th_generation); + + *ffcount += delta; +} + +void +binuptime(struct bintime *bt) +{ + + binuptime_fromclock(bt, sysclock_active); +} + +void +nanouptime(struct timespec *tsp) +{ + + nanouptime_fromclock(tsp, sysclock_active); +} + +void +microuptime(struct timeval *tvp) +{ + + microuptime_fromclock(tvp, sysclock_active); +} + +void +bintime(struct bintime *bt) +{ + + bintime_fromclock(bt, sysclock_active); +} + +void +nanotime(struct timespec *tsp) +{ + + nanotime_fromclock(tsp, sysclock_active); +} + +void +microtime(struct timeval *tvp) +{ + + microtime_fromclock(tvp, sysclock_active); +} + +void +getbinuptime(struct bintime *bt) +{ + + getbinuptime_fromclock(bt, sysclock_active); +} + +void +getnanouptime(struct timespec *tsp) +{ + + getnanouptime_fromclock(tsp, sysclock_active); +} + +void +getmicrouptime(struct timeval *tvp) +{ + + getmicrouptime_fromclock(tvp, sysclock_active); +} + +void +getbintime(struct bintime *bt) +{ + + getbintime_fromclock(bt, sysclock_active); +} + +void +getnanotime(struct timespec *tsp) +{ + + getnanotime_fromclock(tsp, sysclock_active); +} + +void +getmicrotime(struct timeval *tvp) +{ + + getmicrouptime_fromclock(tvp, sysclock_active); +} + +#endif /* FFCLOCK */ + +/* + * This is a clone of getnanotime and used for walltimestamps. + * The dtrace_ prefix prevents fbt from creating probes for + * it so walltimestamp can be safely used in all fbt probes. + */ +void +dtrace_getnanotime(struct timespec *tsp) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + *tsp = th->th_nanotime; + } while (gen == 0 || gen != th->th_generation); +} + +/* + * System clock currently providing time to the system. Modifiable via sysctl + * when the FFCLOCK option is defined. + */ +int sysclock_active = SYSCLOCK_FBCK; + +/* Internal NTP status and error estimates. */ +extern int time_status; +extern long time_esterror; + +/* + * Take a snapshot of sysclock data which can be used to compare system clocks + * and generate timestamps after the fact. + */ +void +sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast) +{ + struct fbclock_info *fbi; + struct timehands *th; + struct bintime bt; + unsigned int delta, gen; +#ifdef FFCLOCK + ffcounter ffcount; + struct fftimehands *ffth; + struct ffclock_info *ffi; + struct ffclock_estimate cest; + + ffi = &clock_snap->ff_info; +#endif + + fbi = &clock_snap->fb_info; + delta = 0; + + do { + th = timehands; + gen = th->th_generation; + fbi->th_scale = th->th_scale; + fbi->tick_time = th->th_offset; +#ifdef FFCLOCK + ffth = fftimehands; + ffi->tick_time = ffth->tick_time_lerp; + ffi->tick_time_lerp = ffth->tick_time_lerp; + ffi->period = ffth->cest.period; + ffi->period_lerp = ffth->period_lerp; + clock_snap->ffcount = ffth->tick_ffcount; + cest = ffth->cest; +#endif + if (!fast) + delta = tc_delta(th); + } while (gen == 0 || gen != th->th_generation); + + clock_snap->delta = delta; + clock_snap->sysclock_active = sysclock_active; + + /* Record feedback clock status and error. */ + clock_snap->fb_info.status = time_status; + /* XXX: Very crude estimate of feedback clock error. */ + bt.sec = time_esterror / 1000000; + bt.frac = ((time_esterror - bt.sec) * 1000000) * + (uint64_t)18446744073709ULL; + clock_snap->fb_info.error = bt; + +#ifdef FFCLOCK + if (!fast) + clock_snap->ffcount += delta; + + /* Record feed-forward clock leap second adjustment. */ + ffi->leapsec_adjustment = cest.leapsec_total; + if (clock_snap->ffcount > cest.leapsec_next) + ffi->leapsec_adjustment -= cest.leapsec; + + /* Record feed-forward clock status and error. */ + clock_snap->ff_info.status = cest.status; + ffcount = clock_snap->ffcount - cest.update_ffcount; + ffclock_convert_delta(ffcount, cest.period, &bt); + /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s]. */ + bintime_mul(&bt, cest.errb_rate * (uint64_t)18446744073709ULL); + /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns]. */ + bintime_addx(&bt, cest.errb_abs * (uint64_t)18446744073ULL); + clock_snap->ff_info.error = bt; +#endif +} + +/* + * Convert a sysclock snapshot into a struct bintime based on the specified + * clock source and flags. + */ +int +sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, + int whichclock, uint32_t flags) +{ +#ifdef FFCLOCK + struct bintime bt2; + uint64_t period; +#endif + + switch (whichclock) { + case SYSCLOCK_FBCK: + *bt = cs->fb_info.tick_time; + + /* If snapshot was created with !fast, delta will be >0. */ + if (cs->delta > 0) + bintime_addx(bt, cs->fb_info.th_scale * cs->delta); + + if ((flags & FBCLOCK_UPTIME) == 0) + bintime_add(bt, &boottimebin); + break; +#ifdef FFCLOCK + case SYSCLOCK_FFWD: + if (flags & FFCLOCK_LERP) { + *bt = cs->ff_info.tick_time_lerp; + period = cs->ff_info.period_lerp; + } else { + *bt = cs->ff_info.tick_time; + period = cs->ff_info.period; + } + + /* If snapshot was created with !fast, delta will be >0. */ + if (cs->delta > 0) { + ffclock_convert_delta(cs->delta, period, &bt2); + bintime_add(bt, &bt2); + } + + /* Leap second adjustment. */ + if (flags & FFCLOCK_LEAPSEC) + bt->sec -= cs->ff_info.leapsec_adjustment; + + /* Boot time adjustment, for uptime/monotonic clocks. */ + if (flags & FFCLOCK_UPTIME) + bintime_sub(bt, &ffclock_boottime); + break; +#endif + default: + return (EINVAL); + break; + } + + return (0); +} + +/* + * Initialize a new timecounter and possibly use it. + */ +void +tc_init(struct timecounter *tc) +{ + u_int u; + struct sysctl_oid *tc_root; + + u = tc->tc_frequency / tc->tc_counter_mask; + /* XXX: We need some margin here, 10% is a guess */ + u *= 11; + u /= 10; + if (u > hz && tc->tc_quality >= 0) { + tc->tc_quality = -2000; + if (bootverbose) { + printf("Timecounter \"%s\" frequency %ju Hz", + tc->tc_name, (uintmax_t)tc->tc_frequency); + printf(" -- Insufficient hz, needs at least %u\n", u); + } + } else if (tc->tc_quality >= 0 || bootverbose) { + printf("Timecounter \"%s\" frequency %ju Hz quality %d\n", + tc->tc_name, (uintmax_t)tc->tc_frequency, + tc->tc_quality); + } + + tc->tc_next = timecounters; + timecounters = tc; + /* + * Set up sysctl tree for this counter. + */ + tc_root = SYSCTL_ADD_NODE(NULL, + SYSCTL_STATIC_CHILDREN(_kern_timecounter_tc), OID_AUTO, tc->tc_name, + CTLFLAG_RW, 0, "timecounter description"); + SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, + "mask", CTLFLAG_RD, &(tc->tc_counter_mask), 0, + "mask for implemented bits"); + SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, + "counter", CTLTYPE_UINT | CTLFLAG_RD, tc, sizeof(*tc), + sysctl_kern_timecounter_get, "IU", "current timecounter value"); + SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, + "frequency", CTLTYPE_U64 | CTLFLAG_RD, tc, sizeof(*tc), + sysctl_kern_timecounter_freq, "QU", "timecounter frequency"); + SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, + "quality", CTLFLAG_RD, &(tc->tc_quality), 0, + "goodness of time counter"); + /* + * Never automatically use a timecounter with negative quality. + * Even though we run on the dummy counter, switching here may be + * worse since this timecounter may not be monotonous. + */ + if (tc->tc_quality < 0) + return; + if (tc->tc_quality < timecounter->tc_quality) + return; + if (tc->tc_quality == timecounter->tc_quality && + tc->tc_frequency < timecounter->tc_frequency) + return; + (void)tc->tc_get_timecount(tc); + (void)tc->tc_get_timecount(tc); + timecounter = tc; +} + +/* Report the frequency of the current timecounter. */ +uint64_t +tc_getfrequency(void) +{ + + return (timehands->th_counter->tc_frequency); +} + +/* + * Step our concept of UTC. This is done by modifying our estimate of + * when we booted. + * XXX: not locked. + */ +void +tc_setclock(struct timespec *ts) +{ + struct timespec tbef, taft; + struct bintime bt, bt2; + + cpu_tick_calibrate(1); + nanotime(&tbef); + timespec2bintime(ts, &bt); + binuptime(&bt2); + bintime_sub(&bt, &bt2); + bintime_add(&bt2, &boottimebin); + boottimebin = bt; + bintime2timeval(&bt, &boottime); + + /* XXX fiddle all the little crinkly bits around the fiords... */ + tc_windup(); + nanotime(&taft); + if (timestepwarnings) { + log(LOG_INFO, + "Time stepped from %jd.%09ld to %jd.%09ld (%jd.%09ld)\n", + (intmax_t)tbef.tv_sec, tbef.tv_nsec, + (intmax_t)taft.tv_sec, taft.tv_nsec, + (intmax_t)ts->tv_sec, ts->tv_nsec); + } + cpu_tick_calibrate(1); +} + +/* + * Initialize the next struct timehands in the ring and make + * it the active timehands. Along the way we might switch to a different + * timecounter and/or do seconds processing in NTP. Slightly magic. + */ +static void +tc_windup(void) +{ + struct bintime bt; + struct timehands *th, *tho; + uint64_t scale; + u_int delta, ncount, ogen; + int i; + time_t t; + + /* + * Make the next timehands a copy of the current one, but do not + * overwrite the generation or next pointer. While we update + * the contents, the generation must be zero. + */ + tho = timehands; + th = tho->th_next; + ogen = th->th_generation; + th->th_generation = 0; + bcopy(tho, th, offsetof(struct timehands, th_generation)); + + /* + * Capture a timecounter delta on the current timecounter and if + * changing timecounters, a counter value from the new timecounter. + * Update the offset fields accordingly. + */ + delta = tc_delta(th); + if (th->th_counter != timecounter) + ncount = timecounter->tc_get_timecount(timecounter); + else + ncount = 0; +#ifdef FFCLOCK + ffclock_windup(delta); +#endif + th->th_offset_count += delta; + th->th_offset_count &= th->th_counter->tc_counter_mask; + while (delta > th->th_counter->tc_frequency) { + /* Eat complete unadjusted seconds. */ + delta -= th->th_counter->tc_frequency; + th->th_offset.sec++; + } + if ((delta > th->th_counter->tc_frequency / 2) && + (th->th_scale * delta < ((uint64_t)1 << 63))) { + /* The product th_scale * delta just barely overflows. */ + th->th_offset.sec++; + } + bintime_addx(&th->th_offset, th->th_scale * delta); + + /* + * Hardware latching timecounters may not generate interrupts on + * PPS events, so instead we poll them. There is a finite risk that + * the hardware might capture a count which is later than the one we + * got above, and therefore possibly in the next NTP second which might + * have a different rate than the current NTP second. It doesn't + * matter in practice. + */ + if (tho->th_counter->tc_poll_pps) + tho->th_counter->tc_poll_pps(tho->th_counter); + + /* + * Deal with NTP second processing. The for loop normally + * iterates at most once, but in extreme situations it might + * keep NTP sane if timeouts are not run for several seconds. + * At boot, the time step can be large when the TOD hardware + * has been read, so on really large steps, we call + * ntp_update_second only twice. We need to call it twice in + * case we missed a leap second. + */ + bt = th->th_offset; + bintime_add(&bt, &boottimebin); + i = bt.sec - tho->th_microtime.tv_sec; + if (i > LARGE_STEP) + i = 2; + for (; i > 0; i--) { + t = bt.sec; + ntp_update_second(&th->th_adjustment, &bt.sec); + if (bt.sec != t) + boottimebin.sec += bt.sec - t; + } + /* Update the UTC timestamps used by the get*() functions. */ + /* XXX shouldn't do this here. Should force non-`get' versions. */ + bintime2timeval(&bt, &th->th_microtime); + bintime2timespec(&bt, &th->th_nanotime); + + /* Now is a good time to change timecounters. */ + if (th->th_counter != timecounter) { +#ifndef __arm__ + if ((timecounter->tc_flags & TC_FLAGS_C2STOP) != 0) + cpu_disable_c2_sleep++; + if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0) + cpu_disable_c2_sleep--; +#endif + th->th_counter = timecounter; + th->th_offset_count = ncount; + tc_min_ticktock_freq = max(1, timecounter->tc_frequency / + (((uint64_t)timecounter->tc_counter_mask + 1) / 3)); +#ifdef FFCLOCK + ffclock_change_tc(th); +#endif + } + + /*- + * Recalculate the scaling factor. We want the number of 1/2^64 + * fractions of a second per period of the hardware counter, taking + * into account the th_adjustment factor which the NTP PLL/adjtime(2) + * processing provides us with. + * + * The th_adjustment is nanoseconds per second with 32 bit binary + * fraction and we want 64 bit binary fraction of second: + * + * x = a * 2^32 / 10^9 = a * 4.294967296 + * + * The range of th_adjustment is +/- 5000PPM so inside a 64bit int + * we can only multiply by about 850 without overflowing, that + * leaves no suitably precise fractions for multiply before divide. + * + * Divide before multiply with a fraction of 2199/512 results in a + * systematic undercompensation of 10PPM of th_adjustment. On a + * 5000PPM adjustment this is a 0.05PPM error. This is acceptable. + * + * We happily sacrifice the lowest of the 64 bits of our result + * to the goddess of code clarity. + * + */ + scale = (uint64_t)1 << 63; + scale += (th->th_adjustment / 1024) * 2199; + scale /= th->th_counter->tc_frequency; + th->th_scale = scale * 2; + + /* + * Now that the struct timehands is again consistent, set the new + * generation number, making sure to not make it zero. + */ + if (++ogen == 0) + ogen = 1; + th->th_generation = ogen; + + /* Go live with the new struct timehands. */ +#ifdef FFCLOCK + switch (sysclock_active) { + case SYSCLOCK_FBCK: +#endif + time_second = th->th_microtime.tv_sec; + time_uptime = th->th_offset.sec; +#ifdef FFCLOCK + break; + case SYSCLOCK_FFWD: + time_second = fftimehands->tick_time_lerp.sec; + time_uptime = fftimehands->tick_time_lerp.sec - ffclock_boottime.sec; + break; + } +#endif + + timehands = th; + timekeep_push_vdso(); +} + +/* Report or change the active timecounter hardware. */ +static int +sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) +{ + char newname[32]; + struct timecounter *newtc, *tc; + int error; + + tc = timecounter; + strlcpy(newname, tc->tc_name, sizeof(newname)); + + error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); + if (error != 0 || req->newptr == NULL || + strcmp(newname, tc->tc_name) == 0) + return (error); + for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) { + if (strcmp(newname, newtc->tc_name) != 0) + continue; + + /* Warm up new timecounter. */ + (void)newtc->tc_get_timecount(newtc); + (void)newtc->tc_get_timecount(newtc); + + timecounter = newtc; + + /* + * The vdso timehands update is deferred until the next + * 'tc_windup()'. + * + * This is prudent given that 'timekeep_push_vdso()' does not + * use any locking and that it can be called in hard interrupt + * context via 'tc_windup()'. + */ + return (0); + } + return (EINVAL); +} + +SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, + 0, 0, sysctl_kern_timecounter_hardware, "A", + "Timecounter hardware selected"); + + +/* Report or change the active timecounter hardware. */ +static int +sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS) +{ + char buf[32], *spc; + struct timecounter *tc; + int error; + + spc = ""; + error = 0; + for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) { + sprintf(buf, "%s%s(%d)", + spc, tc->tc_name, tc->tc_quality); + error = SYSCTL_OUT(req, buf, strlen(buf)); + spc = " "; + } + return (error); +} + +SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, + 0, 0, sysctl_kern_timecounter_choice, "A", "Timecounter hardware detected"); + +/* + * RFC 2783 PPS-API implementation. + */ + +static int +pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) +{ + int err, timo; + pps_seq_t aseq, cseq; + struct timeval tv; + + if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) + return (EINVAL); + + /* + * If no timeout is requested, immediately return whatever values were + * most recently captured. If timeout seconds is -1, that's a request + * to block without a timeout. WITNESS won't let us sleep forever + * without a lock (we really don't need a lock), so just repeatedly + * sleep a long time. + */ + if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) { + if (fapi->timeout.tv_sec == -1) + timo = 0x7fffffff; + else { + tv.tv_sec = fapi->timeout.tv_sec; + tv.tv_usec = fapi->timeout.tv_nsec / 1000; + timo = tvtohz(&tv); + } + aseq = pps->ppsinfo.assert_sequence; + cseq = pps->ppsinfo.clear_sequence; + while (aseq == pps->ppsinfo.assert_sequence && + cseq == pps->ppsinfo.clear_sequence) { + err = tsleep(pps, PCATCH, "ppsfch", timo); + if (err == EWOULDBLOCK && fapi->timeout.tv_sec == -1) { + continue; + } else if (err != 0) { + return (err); + } + } + } + + pps->ppsinfo.current_mode = pps->ppsparam.mode; + fapi->pps_info_buf = pps->ppsinfo; + + return (0); +} + +int +pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) +{ + pps_params_t *app; + struct pps_fetch_args *fapi; +#ifdef FFCLOCK + struct pps_fetch_ffc_args *fapi_ffc; +#endif +#ifdef PPS_SYNC + struct pps_kcbind_args *kapi; +#endif + + KASSERT(pps != NULL, ("NULL pps pointer in pps_ioctl")); + switch (cmd) { + case PPS_IOC_CREATE: + return (0); + case PPS_IOC_DESTROY: + return (0); + case PPS_IOC_SETPARAMS: + app = (pps_params_t *)data; + if (app->mode & ~pps->ppscap) + return (EINVAL); +#ifdef FFCLOCK + /* Ensure only a single clock is selected for ffc timestamp. */ + if ((app->mode & PPS_TSCLK_MASK) == PPS_TSCLK_MASK) + return (EINVAL); +#endif + pps->ppsparam = *app; + return (0); + case PPS_IOC_GETPARAMS: + app = (pps_params_t *)data; + *app = pps->ppsparam; + app->api_version = PPS_API_VERS_1; + return (0); + case PPS_IOC_GETCAP: + *(int*)data = pps->ppscap; + return (0); + case PPS_IOC_FETCH: + fapi = (struct pps_fetch_args *)data; + return (pps_fetch(fapi, pps)); +#ifdef FFCLOCK + case PPS_IOC_FETCH_FFCOUNTER: + fapi_ffc = (struct pps_fetch_ffc_args *)data; + if (fapi_ffc->tsformat && fapi_ffc->tsformat != + PPS_TSFMT_TSPEC) + return (EINVAL); + if (fapi_ffc->timeout.tv_sec || fapi_ffc->timeout.tv_nsec) + return (EOPNOTSUPP); + pps->ppsinfo_ffc.current_mode = pps->ppsparam.mode; + fapi_ffc->pps_info_buf_ffc = pps->ppsinfo_ffc; + /* Overwrite timestamps if feedback clock selected. */ + switch (pps->ppsparam.mode & PPS_TSCLK_MASK) { + case PPS_TSCLK_FBCK: + fapi_ffc->pps_info_buf_ffc.assert_timestamp = + pps->ppsinfo.assert_timestamp; + fapi_ffc->pps_info_buf_ffc.clear_timestamp = + pps->ppsinfo.clear_timestamp; + break; + case PPS_TSCLK_FFWD: + break; + default: + break; + } + return (0); +#endif /* FFCLOCK */ + case PPS_IOC_KCBIND: +#ifdef PPS_SYNC + kapi = (struct pps_kcbind_args *)data; + /* XXX Only root should be able to do this */ + if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) + return (EINVAL); + if (kapi->kernel_consumer != PPS_KC_HARDPPS) + return (EINVAL); + if (kapi->edge & ~pps->ppscap) + return (EINVAL); + pps->kcmode = kapi->edge; + return (0); +#else + return (EOPNOTSUPP); +#endif + default: + return (ENOIOCTL); + } +} + +void +pps_init(struct pps_state *pps) +{ + pps->ppscap |= PPS_TSFMT_TSPEC | PPS_CANWAIT; + if (pps->ppscap & PPS_CAPTUREASSERT) + pps->ppscap |= PPS_OFFSETASSERT; + if (pps->ppscap & PPS_CAPTURECLEAR) + pps->ppscap |= PPS_OFFSETCLEAR; +#ifdef FFCLOCK + pps->ppscap |= PPS_TSCLK_MASK; +#endif +} + +void +pps_capture(struct pps_state *pps) +{ + struct timehands *th; + + KASSERT(pps != NULL, ("NULL pps pointer in pps_capture")); + th = timehands; + pps->capgen = th->th_generation; + pps->capth = th; +#ifdef FFCLOCK + pps->capffth = fftimehands; +#endif + pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); + if (pps->capgen != th->th_generation) + pps->capgen = 0; +} + +void +pps_event(struct pps_state *pps, int event) +{ + struct bintime bt; + struct timespec ts, *tsp, *osp; + u_int tcount, *pcount; + int foff, fhard; + pps_seq_t *pseq; +#ifdef FFCLOCK + struct timespec *tsp_ffc; + pps_seq_t *pseq_ffc; + ffcounter *ffcount; +#endif + + KASSERT(pps != NULL, ("NULL pps pointer in pps_event")); + /* If the timecounter was wound up underneath us, bail out. */ + if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation) + return; + + /* Things would be easier with arrays. */ + if (event == PPS_CAPTUREASSERT) { + tsp = &pps->ppsinfo.assert_timestamp; + osp = &pps->ppsparam.assert_offset; + foff = pps->ppsparam.mode & PPS_OFFSETASSERT; + fhard = pps->kcmode & PPS_CAPTUREASSERT; + pcount = &pps->ppscount[0]; + pseq = &pps->ppsinfo.assert_sequence; +#ifdef FFCLOCK + ffcount = &pps->ppsinfo_ffc.assert_ffcount; + tsp_ffc = &pps->ppsinfo_ffc.assert_timestamp; + pseq_ffc = &pps->ppsinfo_ffc.assert_sequence; +#endif + } else { + tsp = &pps->ppsinfo.clear_timestamp; + osp = &pps->ppsparam.clear_offset; + foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; + fhard = pps->kcmode & PPS_CAPTURECLEAR; + pcount = &pps->ppscount[1]; + pseq = &pps->ppsinfo.clear_sequence; +#ifdef FFCLOCK + ffcount = &pps->ppsinfo_ffc.clear_ffcount; + tsp_ffc = &pps->ppsinfo_ffc.clear_timestamp; + pseq_ffc = &pps->ppsinfo_ffc.clear_sequence; +#endif + } + + /* + * If the timecounter changed, we cannot compare the count values, so + * we have to drop the rest of the PPS-stuff until the next event. + */ + if (pps->ppstc != pps->capth->th_counter) { + pps->ppstc = pps->capth->th_counter; + *pcount = pps->capcount; + pps->ppscount[2] = pps->capcount; + return; + } + + /* Convert the count to a timespec. */ + tcount = pps->capcount - pps->capth->th_offset_count; + tcount &= pps->capth->th_counter->tc_counter_mask; + bt = pps->capth->th_offset; + bintime_addx(&bt, pps->capth->th_scale * tcount); + bintime_add(&bt, &boottimebin); + bintime2timespec(&bt, &ts); + + /* If the timecounter was wound up underneath us, bail out. */ + if (pps->capgen != pps->capth->th_generation) + return; + + *pcount = pps->capcount; + (*pseq)++; + *tsp = ts; + + if (foff) { + timespecadd(tsp, osp); + if (tsp->tv_nsec < 0) { + tsp->tv_nsec += 1000000000; + tsp->tv_sec -= 1; + } + } + +#ifdef FFCLOCK + *ffcount = pps->capffth->tick_ffcount + tcount; + bt = pps->capffth->tick_time; + ffclock_convert_delta(tcount, pps->capffth->cest.period, &bt); + bintime_add(&bt, &pps->capffth->tick_time); + bintime2timespec(&bt, &ts); + (*pseq_ffc)++; + *tsp_ffc = ts; +#endif + +#ifdef PPS_SYNC + if (fhard) { + uint64_t scale; + + /* + * Feed the NTP PLL/FLL. + * The FLL wants to know how many (hardware) nanoseconds + * elapsed since the previous event. + */ + tcount = pps->capcount - pps->ppscount[2]; + pps->ppscount[2] = pps->capcount; + tcount &= pps->capth->th_counter->tc_counter_mask; + scale = (uint64_t)1 << 63; + scale /= pps->capth->th_counter->tc_frequency; + scale *= 2; + bt.sec = 0; + bt.frac = 0; + bintime_addx(&bt, scale * tcount); + bintime2timespec(&bt, &ts); + hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec); + } +#endif + + /* Wakeup anyone sleeping in pps_fetch(). */ + wakeup(pps); +} + +/* + * Timecounters need to be updated every so often to prevent the hardware + * counter from overflowing. Updating also recalculates the cached values + * used by the get*() family of functions, so their precision depends on + * the update frequency. + */ + +static int tc_tick; +SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, + "Approximate number of hardclock ticks in a millisecond"); + +void +tc_ticktock(int cnt) +{ + static int count; + + count += cnt; + if (count < tc_tick) + return; + count = 0; + tc_windup(); +} + +static void __inline +tc_adjprecision(void) +{ + int t; + + if (tc_timepercentage > 0) { + t = (99 + tc_timepercentage) / tc_timepercentage; + tc_precexp = fls(t + (t >> 1)) - 1; + FREQ2BT(hz / tc_tick, &bt_timethreshold); + FREQ2BT(hz, &bt_tickthreshold); + bintime_shift(&bt_timethreshold, tc_precexp); + bintime_shift(&bt_tickthreshold, tc_precexp); + } else { + tc_precexp = 31; + bt_timethreshold.sec = INT_MAX; + bt_timethreshold.frac = ~(uint64_t)0; + bt_tickthreshold = bt_timethreshold; + } + sbt_timethreshold = bttosbt(bt_timethreshold); + sbt_tickthreshold = bttosbt(bt_tickthreshold); +} + +static int +sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS) +{ + int error, val; + + val = tc_timepercentage; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + tc_timepercentage = val; + if (cold) + goto done; + tc_adjprecision(); +done: + return (0); +} + +static void +inittimecounter(void *dummy) +{ + u_int p; + int tick_rate; + + /* + * Set the initial timeout to + * max(1, ). + * People should probably not use the sysctl to set the timeout + * to smaller than its inital value, since that value is the + * smallest reasonable one. If they want better timestamps they + * should use the non-"get"* functions. + */ + if (hz > 1000) + tc_tick = (hz + 500) / 1000; + else + tc_tick = 1; + tc_adjprecision(); + FREQ2BT(hz, &tick_bt); + tick_sbt = bttosbt(tick_bt); + tick_rate = hz / tc_tick; + FREQ2BT(tick_rate, &tc_tick_bt); + tc_tick_sbt = bttosbt(tc_tick_bt); + p = (tc_tick * 1000000) / hz; + printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); + +#ifdef FFCLOCK + ffclock_init(); +#endif + /* warm up new timecounter (again) and get rolling. */ + (void)timecounter->tc_get_timecount(timecounter); + (void)timecounter->tc_get_timecount(timecounter); + tc_windup(); +} + +SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); + +/* Cpu tick handling -------------------------------------------------*/ + +static int cpu_tick_variable; +static uint64_t cpu_tick_frequency; + +static uint64_t +tc_cpu_ticks(void) +{ + static uint64_t base; + static unsigned last; + unsigned u; + struct timecounter *tc; + + tc = timehands->th_counter; + u = tc->tc_get_timecount(tc) & tc->tc_counter_mask; + if (u < last) + base += (uint64_t)tc->tc_counter_mask + 1; + last = u; + return (u + base); +} + +void +cpu_tick_calibration(void) +{ + static time_t last_calib; + + if (time_uptime != last_calib && !(time_uptime & 0xf)) { + cpu_tick_calibrate(0); + last_calib = time_uptime; + } +} + +/* + * This function gets called every 16 seconds on only one designated + * CPU in the system from hardclock() via cpu_tick_calibration()(). + * + * Whenever the real time clock is stepped we get called with reset=1 + * to make sure we handle suspend/resume and similar events correctly. + */ + +static void +cpu_tick_calibrate(int reset) +{ + static uint64_t c_last; + uint64_t c_this, c_delta; + static struct bintime t_last; + struct bintime t_this, t_delta; + uint32_t divi; + + if (reset) { + /* The clock was stepped, abort & reset */ + t_last.sec = 0; + return; + } + + /* we don't calibrate fixed rate cputicks */ + if (!cpu_tick_variable) + return; + + getbinuptime(&t_this); + c_this = cpu_ticks(); + if (t_last.sec != 0) { + c_delta = c_this - c_last; + t_delta = t_this; + bintime_sub(&t_delta, &t_last); + /* + * Headroom: + * 2^(64-20) / 16[s] = + * 2^(44) / 16[s] = + * 17.592.186.044.416 / 16 = + * 1.099.511.627.776 [Hz] + */ + divi = t_delta.sec << 20; + divi |= t_delta.frac >> (64 - 20); + c_delta <<= 20; + c_delta /= divi; + if (c_delta > cpu_tick_frequency) { + if (0 && bootverbose) + printf("cpu_tick increased to %ju Hz\n", + c_delta); + cpu_tick_frequency = c_delta; + } + } + c_last = c_this; + t_last = t_this; +} + +void +set_cputicker(cpu_tick_f *func, uint64_t freq, unsigned var) +{ + + if (func == NULL) { + cpu_ticks = tc_cpu_ticks; + } else { + cpu_tick_frequency = freq; + cpu_tick_variable = var; + cpu_ticks = func; + } +} + +uint64_t +cpu_tickrate(void) +{ + + if (cpu_ticks == tc_cpu_ticks) + return (tc_getfrequency()); + return (cpu_tick_frequency); +} + +/* + * We need to be slightly careful converting cputicks to microseconds. + * There is plenty of margin in 64 bits of microseconds (half a million + * years) and in 64 bits at 4 GHz (146 years), but if we do a multiply + * before divide conversion (to retain precision) we find that the + * margin shrinks to 1.5 hours (one millionth of 146y). + * With a three prong approach we never lose significant bits, no + * matter what the cputick rate and length of timeinterval is. + */ + +uint64_t +cputick2usec(uint64_t tick) +{ + + if (tick > 18446744073709551LL) /* floor(2^64 / 1000) */ + return (tick / (cpu_tickrate() / 1000000LL)); + else if (tick > 18446744073709LL) /* floor(2^64 / 1000000) */ + return ((tick * 1000LL) / (cpu_tickrate() / 1000LL)); + else + return ((tick * 1000000LL) / cpu_tickrate()); +} + +cpu_tick_f *cpu_ticks = tc_cpu_ticks; + +static int vdso_th_enable = 1; +static int +sysctl_fast_gettime(SYSCTL_HANDLER_ARGS) +{ + int old_vdso_th_enable, error; + + old_vdso_th_enable = vdso_th_enable; + error = sysctl_handle_int(oidp, &old_vdso_th_enable, 0, req); + if (error != 0) + return (error); + vdso_th_enable = old_vdso_th_enable; + return (0); +} +SYSCTL_PROC(_kern_timecounter, OID_AUTO, fast_gettime, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + NULL, 0, sysctl_fast_gettime, "I", "Enable fast time of day"); + +uint32_t +tc_fill_vdso_timehands(struct vdso_timehands *vdso_th) +{ + struct timehands *th; + uint32_t enabled; + + th = timehands; + vdso_th->th_algo = VDSO_TH_ALGO_1; + vdso_th->th_scale = th->th_scale; + vdso_th->th_offset_count = th->th_offset_count; + vdso_th->th_counter_mask = th->th_counter->tc_counter_mask; + vdso_th->th_offset = th->th_offset; + vdso_th->th_boottime = boottimebin; + enabled = cpu_fill_vdso_timehands(vdso_th, th->th_counter); + if (!vdso_th_enable) + enabled = 0; + return (enabled); +} + +#ifdef COMPAT_FREEBSD32 +uint32_t +tc_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32) +{ + struct timehands *th; + uint32_t enabled; + + th = timehands; + vdso_th32->th_algo = VDSO_TH_ALGO_1; + *(uint64_t *)&vdso_th32->th_scale[0] = th->th_scale; + vdso_th32->th_offset_count = th->th_offset_count; + vdso_th32->th_counter_mask = th->th_counter->tc_counter_mask; + vdso_th32->th_offset.sec = th->th_offset.sec; + *(uint64_t *)&vdso_th32->th_offset.frac[0] = th->th_offset.frac; + vdso_th32->th_boottime.sec = boottimebin.sec; + *(uint64_t *)&vdso_th32->th_boottime.frac[0] = boottimebin.frac; + enabled = cpu_fill_vdso_timehands32(vdso_th32, th->th_counter); + if (!vdso_th_enable) + enabled = 0; + return (enabled); +} +#endif diff --git a/cpukit/score/src/opt_compat.h b/cpukit/score/src/opt_compat.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpukit/score/src/opt_ffclock.h b/cpukit/score/src/opt_ffclock.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpukit/score/src/opt_ntp.h b/cpukit/score/src/opt_ntp.h new file mode 100644 index 0000000000..e69de29bb2 -- cgit v1.2.3 From 664f8446f4388a0c54b15239aec08210eb8b6eac Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Tue, 12 May 2015 12:10:04 +0200 Subject: timecounter: Use uint32_t instead of u_int FreeBSD assumes that u_int is a 32-bit integer type. This is wrong for some 16-bit targets supported by RTEMS. Update #2271. --- cpukit/score/include/sys/timetc.h | 4 ++-- cpukit/score/src/kern_tc.c | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cpukit/score/include/sys/timetc.h b/cpukit/score/include/sys/timetc.h index f553101b71..9d269a780b 100644 --- a/cpukit/score/include/sys/timetc.h +++ b/cpukit/score/include/sys/timetc.h @@ -28,7 +28,7 @@ */ struct timecounter; -typedef u_int timecounter_get_t(struct timecounter *); +typedef uint32_t timecounter_get_t(struct timecounter *); typedef void timecounter_pps_t(struct timecounter *); struct timecounter { @@ -45,7 +45,7 @@ struct timecounter { * events. Normal hardware does not need it but timecounters * which latch PPS in hardware (like sys/pci/xrpu.c) do. */ - u_int tc_counter_mask; + uint32_t tc_counter_mask; /* This mask should mask off any unimplemented bits. */ uint64_t tc_frequency; /* Frequency of the counter in Hz. */ diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index 82e5e1e50c..8bcb9b843b 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -50,10 +50,10 @@ __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); * time services. */ -static u_int +static uint32_t dummy_get_timecount(struct timecounter *tc) { - static u_int now; + static uint32_t now; return (++now); } @@ -67,12 +67,12 @@ struct timehands { struct timecounter *th_counter; int64_t th_adjustment; uint64_t th_scale; - u_int th_offset_count; + uint32_t th_offset_count; struct bintime th_offset; struct timeval th_microtime; struct timespec th_nanotime; /* Fields not to be copied in tc_windup start with th_generation. */ - volatile u_int th_generation; + volatile uint32_t th_generation; struct timehands *th_next; }; @@ -159,7 +159,7 @@ sysctl_kern_boottime(SYSCTL_HANDLER_ARGS) static int sysctl_kern_timecounter_get(SYSCTL_HANDLER_ARGS) { - u_int ncount; + uint32_t ncount; struct timecounter *tc = arg1; ncount = tc->tc_get_timecount(tc); @@ -180,7 +180,7 @@ sysctl_kern_timecounter_freq(SYSCTL_HANDLER_ARGS) * Return the difference between the timehands' counter value now and what * was when we copied it to the timehands' offset_count. */ -static __inline u_int +static __inline uint32_t tc_delta(struct timehands *th) { struct timecounter *tc; @@ -338,7 +338,7 @@ void binuptime(struct bintime *bt) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -396,7 +396,7 @@ void getbinuptime(struct bintime *bt) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -409,7 +409,7 @@ void getnanouptime(struct timespec *tsp) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -422,7 +422,7 @@ void getmicrouptime(struct timeval *tvp) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -435,7 +435,7 @@ void getbintime(struct bintime *bt) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -449,7 +449,7 @@ void getnanotime(struct timespec *tsp) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -462,7 +462,7 @@ void getmicrotime(struct timeval *tvp) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -985,7 +985,7 @@ void dtrace_getnanotime(struct timespec *tsp) { struct timehands *th; - u_int gen; + uint32_t gen; do { th = timehands; @@ -1140,7 +1140,7 @@ sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, void tc_init(struct timecounter *tc) { - u_int u; + uint32_t u; struct sysctl_oid *tc_root; u = tc->tc_frequency / tc->tc_counter_mask; @@ -1249,7 +1249,7 @@ tc_windup(void) struct bintime bt; struct timehands *th, *tho; uint64_t scale; - u_int delta, ncount, ogen; + uint32_t delta, ncount, ogen; int i; time_t t; @@ -1633,7 +1633,7 @@ pps_event(struct pps_state *pps, int event) { struct bintime bt; struct timespec ts, *tsp, *osp; - u_int tcount, *pcount; + uint32_t tcount, *pcount; int foff, fhard; pps_seq_t *pseq; #ifdef FFCLOCK -- cgit v1.2.3 From cc6938455edfa4dff79ce98320292e3a9c2e434b Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Tue, 12 May 2015 12:12:18 +0200 Subject: timecounter: Honor FFCLOCK define Update #2271. --- cpukit/score/src/kern_tc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index 8bcb9b843b..246c98bb90 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -994,11 +994,13 @@ dtrace_getnanotime(struct timespec *tsp) } while (gen == 0 || gen != th->th_generation); } +#ifdef FFCLOCK /* * System clock currently providing time to the system. Modifiable via sysctl * when the FFCLOCK option is defined. */ int sysclock_active = SYSCLOCK_FBCK; +#endif /* Internal NTP status and error estimates. */ extern int time_status; @@ -1046,7 +1048,9 @@ sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast) } while (gen == 0 || gen != th->th_generation); clock_snap->delta = delta; +#ifdef FFCLOCK clock_snap->sysclock_active = sysclock_active; +#endif /* Record feedback clock status and error. */ clock_snap->fb_info.status = time_status; -- cgit v1.2.3 From 31be41653a659a52460734cb8fe1da27e6d5629e Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Mon, 20 Apr 2015 11:08:22 +0200 Subject: timecounter: Port to RTEMS New test sptests/timecounter01. Update #2271. --- cpukit/sapi/Makefile.am | 3 + cpukit/sapi/include/rtems/bsd.h | 141 ++++++++++ cpukit/sapi/include/rtems/timecounter.h | 304 +++++++++++++++++++++ cpukit/sapi/preinstall.am | 8 + cpukit/sapi/src/tcsimpleinstall.c | 52 ++++ cpukit/score/Makefile.am | 12 + cpukit/score/include/rtems/score/timecounter.h | 199 ++++++++++++++ cpukit/score/include/rtems/score/timecounterimpl.h | 49 ++++ cpukit/score/include/sys/timeffc.h | 2 + cpukit/score/include/sys/timetc.h | 2 + cpukit/score/preinstall.am | 33 +++ cpukit/score/src/kern_tc.c | 171 ++++++++++++ doc/bsp_howto/clock.t | 302 ++++++++++++++++---- testsuites/sptests/Makefile.am | 1 + testsuites/sptests/configure.ac | 1 + testsuites/sptests/sptimecounter01/Makefile.am | 19 ++ testsuites/sptests/sptimecounter01/init.c | 133 +++++++++ .../sptests/sptimecounter01/sptimecounter01.doc | 29 ++ .../sptests/sptimecounter01/sptimecounter01.scn | 2 + 19 files changed, 1411 insertions(+), 52 deletions(-) create mode 100644 cpukit/sapi/include/rtems/bsd.h create mode 100644 cpukit/sapi/include/rtems/timecounter.h create mode 100644 cpukit/sapi/src/tcsimpleinstall.c create mode 100644 cpukit/score/include/rtems/score/timecounter.h create mode 100644 cpukit/score/include/rtems/score/timecounterimpl.h create mode 100644 testsuites/sptests/sptimecounter01/Makefile.am create mode 100644 testsuites/sptests/sptimecounter01/init.c create mode 100644 testsuites/sptests/sptimecounter01/sptimecounter01.doc create mode 100644 testsuites/sptests/sptimecounter01/sptimecounter01.scn diff --git a/cpukit/sapi/Makefile.am b/cpukit/sapi/Makefile.am index 070800e636..d7fd9aac63 100644 --- a/cpukit/sapi/Makefile.am +++ b/cpukit/sapi/Makefile.am @@ -4,6 +4,7 @@ include $(top_srcdir)/automake/compile.am include_rtemsdir = $(includedir)/rtems include_rtems_HEADERS = include/confdefs.h +include_rtems_HEADERS += include/rtems/bsd.h include_rtems_HEADERS += include/rtems/chain.h include_rtems_HEADERS += include/rtems/config.h include_rtems_HEADERS += include/rtems/counter.h @@ -19,6 +20,7 @@ include_rtems_HEADERS += include/rtems/rbheap.h include_rtems_HEADERS += include/rtems/rbtree.h include_rtems_HEADERS += include/rtems/scheduler.h include_rtems_HEADERS += include/rtems/sptables.h +include_rtems_HEADERS += include/rtems/timecounter.h include_rtems_HEADERS += include/rtems/timespec.h EXTRA_DIST = include/rtems/README @@ -39,6 +41,7 @@ libsapi_a_SOURCES += src/delayticks.c libsapi_a_SOURCES += src/delaynano.c libsapi_a_SOURCES += src/profilingiterate.c libsapi_a_SOURCES += src/profilingreportxml.c +libsapi_a_SOURCES += src/tcsimpleinstall.c libsapi_a_CPPFLAGS = $(AM_CPPFLAGS) include $(srcdir)/preinstall.am diff --git a/cpukit/sapi/include/rtems/bsd.h b/cpukit/sapi/include/rtems/bsd.h new file mode 100644 index 0000000000..0c44e3787d --- /dev/null +++ b/cpukit/sapi/include/rtems/bsd.h @@ -0,0 +1,141 @@ +/** + * @file + * + * @ingroup BSD + * + * @brief BSD Compatibility API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef _RTEMS_BSD_H +#define _RTEMS_BSD_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup BSD BSD Compatibility Support + * + * @{ + */ + +/** + * @copydoc _Timecounter_Bintime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_bintime( struct bintime *bt ) +{ + _Timecounter_Bintime( bt ); +} + +/** + * @copydoc _Timecounter_Nanotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_nanotime( struct timespec *ts ) +{ + _Timecounter_Nanotime( ts ); +} + +/** + * @copydoc _Timecounter_Microtime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_microtime( struct timeval *tv ) +{ + _Timecounter_Microtime( tv ); +} + +/** + * @copydoc _Timecounter_Binuptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_binuptime( struct bintime *bt ) +{ + _Timecounter_Binuptime( bt ); +} + +/** + * @copydoc _Timecounter_Nanouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_nanouptime( struct timespec *ts ) +{ + _Timecounter_Nanouptime( ts ); +} + +/** + * @copydoc _Timecounter_Microtime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_microuptime( struct timeval *tv ) +{ + _Timecounter_Microuptime( tv ); +} + +/** + * @copydoc _Timecounter_Getbintime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getbintime( struct bintime *bt ) +{ + _Timecounter_Getbintime( bt ); +} + +/** + * @copydoc _Timecounter_Getnanotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getnanotime( struct timespec *ts ) +{ + _Timecounter_Getnanotime( ts ); +} + +/** + * @copydoc _Timecounter_Getmicrotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getmicrotime( struct timeval *tv ) +{ + _Timecounter_Getmicrotime( tv ); +} + +/** + * @copydoc _Timecounter_Getbinuptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getbinuptime( struct bintime *bt ) +{ + _Timecounter_Getbinuptime( bt ); +} + +/** + * @copydoc _Timecounter_Getnanouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getnanouptime( struct timespec *ts ) +{ + _Timecounter_Getnanouptime( ts ); +} + +/** + * @copydoc _Timecounter_Getmicrouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getmicrouptime( struct timeval *tv ) +{ + _Timecounter_Getmicrouptime( tv ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_BSD_H */ diff --git a/cpukit/sapi/include/rtems/timecounter.h b/cpukit/sapi/include/rtems/timecounter.h new file mode 100644 index 0000000000..04bc534d55 --- /dev/null +++ b/cpukit/sapi/include/rtems/timecounter.h @@ -0,0 +1,304 @@ +/** + * @file + * + * @ingroup SAPITimecounter + * + * @brief Timecounter API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef _RTEMS_TIMECOUNTER_H +#define _RTEMS_TIMECOUNTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup SAPITimecounter Timecounter Support + * + * @{ + */ + +/** + * @brief Timecounter quality for the clock drivers. + * + * Timecounter with higher quality value are used in favour of those with lower + * quality value. + */ +#define RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER 100 + +/** + * @copydoc _Timecounter_Install() + * + * Below is an exemplary code snippet that shows the adjustable parameters and + * the following call of the install routine. + * + * @code + * struct timecounter tc; + * + * uint32_t get_timecount( struct timecounter *tc ) + * { + * return some_free_running_counter; + * } + * + * void install( void ) + * { + * tc.tc_get_timecount = get_timecount; + * tc.tc_counter_mask = 0xffffffff; + * tc.tc_frequency = 123456; + * tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + * rtems_timecounter_install( &tc ); + * } + * @endcode + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_install( + struct timecounter *tc +) +{ + _Timecounter_Install( tc ); +} + +/** + * @copydoc _Timecounter_Tick() + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_tick(void) +{ + _Timecounter_Tick(); +} + +/** + * @brief Simple timecounter to support legacy clock drivers. + */ +typedef struct { + struct timecounter tc; + uint64_t scaler; + uint32_t real_interval; + uint32_t binary_interval; +} rtems_timecounter_simple; + +/** + * @brief Returns the current value of a simple timecounter. + */ +typedef uint32_t rtems_timecounter_simple_get( + rtems_timecounter_simple *tc +); + +/** + * @brief Returns true if the interrupt of a simple timecounter is pending, and + * false otherwise. + */ +typedef bool rtems_timecounter_simple_is_pending( + rtems_timecounter_simple *tc +); + +/** + * @brief Initializes and installs a simple timecounter. + * + * A simple timecounter can be used if the hardware provides no free running + * counter or only the module used for the clock tick is available. The period + * of the simple timecounter equals the clock tick interval. The interval is + * scaled up to the next power of two. + * + * @param[in] tc Zero initialized simple timecounter. + * @param[in] frequency_in_hz The timecounter frequency in Hz. + * @param[in] timecounter_ticks_per_clock_tick The timecounter ticks per clock tick. + * @param[in] get_timecount The method to get the current time count. + * + * @code + * #include + * + * static rtems_timecounter_simple some_tc; + * + * static uint32_t some_tc_get( rtems_timecounter_simple *tc ) + * { + * return some.value; + * } + * + * static bool some_tc_is_pending( rtems_timecounter_simple *tc ) + * { + * return some.is_pending; + * } + * + * static uint32_t some_tc_get_timecount( struct timecounter *tc ) + * { + * return rtems_timecounter_simple_downcounter_get( + * tc, + * some_tc_get, + * some_tc_is_pending + * ); + * } + * + * static void some_tc_tick( void ) + * { + * rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get ); + * } + * + * void install( void ) + * { + * uint32_t frequency = 123456; + * uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + * uint32_t timecounter_ticks_per_clock_tick = + * ( frequency * us_per_tick ) / 1000000; + * + * rtems_timecounter_simple_install( + * &some_tc, + * frequency, + * timecounter_ticks_per_clock_tick, + * some_tc_get_timecount + * ); + * } + * @endcode + * + * @see rtems_timecounter_simple_downcounter_get(), + * rtems_timecounter_simple_downcounter_tick(), + * rtems_timecounter_simple_upcounter_get() and + * rtems_timecounter_simple_upcounter_tick(). + */ +void rtems_timecounter_simple_install( + rtems_timecounter_simple *tc, + uint32_t frequency_in_hz, + uint32_t timecounter_ticks_per_clock_tick, + timecounter_get_t *get_timecount +); + +/** + * @brief Maps a simple timecounter value into its binary frequency domain. + * + * @param[in] tc The simple timecounter. + * @param[in] value The value of the simple timecounter. + * + * @return The scaled value. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_scale( + const rtems_timecounter_simple *tc, + uint32_t value +) +{ + return (uint32_t) ( ( value * tc->scaler ) >> 32 ); +} + +/** + * @brief Performs a simple timecounter tick for downcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_downcounter_tick( + rtems_timecounter_simple *tc, + rtems_timecounter_simple_get get +) +{ + uint32_t current; + + current = rtems_timecounter_simple_scale( + tc, + tc->real_interval - ( *get )( tc ) + ); + + _Timecounter_Tick_simple( tc->binary_interval, current ); +} + +/** + * @brief Performs a simple timecounter tick for upcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_upcounter_tick( + rtems_timecounter_simple *tc, + rtems_timecounter_simple_get get +) +{ + uint32_t current; + + current = rtems_timecounter_simple_scale( tc, ( *get )( tc ) ); + + _Timecounter_Tick_simple( tc->binary_interval, current ); +} + +/** + * @brief Gets the simple timecounter value mapped to its binary frequency + * domain for downcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + * @param[in] is_pending The method which indicates if the interrupt of the + * simple timecounter is pending. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_downcounter_get( + struct timecounter *tc_base, + rtems_timecounter_simple_get get, + rtems_timecounter_simple_is_pending is_pending +) +{ + rtems_timecounter_simple *tc; + uint32_t counter; + uint32_t interval; + + tc = (rtems_timecounter_simple *) tc_base; + counter = ( *get )( tc ); + interval = tc->real_interval; + + if ( ( *is_pending )( tc ) ) { + counter = ( *get )( tc ); + interval *= 2; + } + + return rtems_timecounter_simple_scale( tc, interval - counter ); +} + +/** + * @brief Gets the simple timecounter value mapped to its binary frequency + * domain for upcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + * @param[in] is_pending The method which indicates if the interrupt of the + * simple timecounter is pending. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_upcounter_get( + struct timecounter *tc_base, + rtems_timecounter_simple_get get, + rtems_timecounter_simple_is_pending is_pending +) +{ + rtems_timecounter_simple *tc; + uint32_t counter; + uint32_t interval; + + tc = (rtems_timecounter_simple *) tc_base; + counter = ( *get )( tc ); + interval = 0; + + if ( ( *is_pending )( tc ) ) { + counter = ( *get )( tc ); + interval = tc->real_interval; + } + + return rtems_timecounter_simple_scale( tc, interval + counter ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_TIMECOUNTER_H */ diff --git a/cpukit/sapi/preinstall.am b/cpukit/sapi/preinstall.am index 3f864bb61d..8a4e54ffd2 100644 --- a/cpukit/sapi/preinstall.am +++ b/cpukit/sapi/preinstall.am @@ -22,6 +22,10 @@ $(PROJECT_INCLUDE)/rtems/confdefs.h: include/confdefs.h $(PROJECT_INCLUDE)/rtems $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/confdefs.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/confdefs.h +$(PROJECT_INCLUDE)/rtems/bsd.h: include/rtems/bsd.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bsd.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bsd.h + $(PROJECT_INCLUDE)/rtems/chain.h: include/rtems/chain.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/chain.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/chain.h @@ -82,6 +86,10 @@ $(PROJECT_INCLUDE)/rtems/sptables.h: include/rtems/sptables.h $(PROJECT_INCLUDE) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/sptables.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/sptables.h +$(PROJECT_INCLUDE)/rtems/timecounter.h: include/rtems/timecounter.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/timecounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/timecounter.h + $(PROJECT_INCLUDE)/rtems/timespec.h: include/rtems/timespec.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/timespec.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/timespec.h diff --git a/cpukit/sapi/src/tcsimpleinstall.c b/cpukit/sapi/src/tcsimpleinstall.c new file mode 100644 index 0000000000..563edd7c87 --- /dev/null +++ b/cpukit/sapi/src/tcsimpleinstall.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 + +void rtems_timecounter_simple_install( + rtems_timecounter_simple *tc, + uint32_t frequency_in_hz, + uint32_t counter_ticks_per_clock_tick, + timecounter_get_t *get_timecount +) +{ + uint32_t power_of_two = 1; + uint32_t mask; + uint64_t scaler; + int i; + + for ( i = 0; i < 32; ++i ) { + if ( power_of_two >= counter_ticks_per_clock_tick ) { + break; + } + + power_of_two *= 2; + } + + mask = ( 2 * power_of_two ) - 1; + scaler = ( (uint64_t) power_of_two << 32 ) / counter_ticks_per_clock_tick; + + tc->scaler = scaler; + tc->real_interval = counter_ticks_per_clock_tick; + tc->binary_interval = ( mask + 1 ) / 2; + tc->tc.tc_get_timecount = get_timecount; + tc->tc.tc_counter_mask = mask; + tc->tc.tc_frequency = (uint32_t) ( ( frequency_in_hz * scaler ) >> 32 ); + tc->tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + _Timecounter_Install( &tc->tc ); +} diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index b6b7c9fa74..a16aedac1d 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -5,6 +5,15 @@ SUBDIRS = cpu ## include +include_sysdir = $(includedir)/sys + +include_sys_HEADERS = +include_sys_HEADERS += include/sys/_ffcounter.h +include_sys_HEADERS += include/sys/timeffc.h +include_sys_HEADERS += include/sys/timepps.h +include_sys_HEADERS += include/sys/timetc.h +include_sys_HEADERS += include/sys/timex.h + include_rtemsdir = $(includedir)/rtems include_rtems_HEADERS = include/rtems/debug.h @@ -85,6 +94,8 @@ include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h include_rtems_score_HEADERS += include/rtems/score/timespec.h include_rtems_score_HEADERS += include/rtems/score/timestamp.h include_rtems_score_HEADERS += include/rtems/score/timestamp64.h +include_rtems_score_HEADERS += include/rtems/score/timecounter.h +include_rtems_score_HEADERS += include/rtems/score/timecounterimpl.h include_rtems_score_HEADERS += include/rtems/score/tls.h include_rtems_score_HEADERS += include/rtems/score/tod.h include_rtems_score_HEADERS += include/rtems/score/todimpl.h @@ -344,6 +355,7 @@ libscore_a_SOURCES += src/profilingisrentryexit.c libscore_a_SOURCES += src/once.c libscore_a_SOURCES += src/resourceiterate.c libscore_a_SOURCES += src/smpbarrierwait.c +libscore_a_SOURCES += src/kern_tc.c EXTRA_DIST = src/Unlimited.txt diff --git a/cpukit/score/include/rtems/score/timecounter.h b/cpukit/score/include/rtems/score/timecounter.h new file mode 100644 index 0000000000..0d17cc7ce3 --- /dev/null +++ b/cpukit/score/include/rtems/score/timecounter.h @@ -0,0 +1,199 @@ +/** + * @file + * + * @ingroup ScoreTimecounter + * + * @brief Timecounter API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef _RTEMS_SCORE_TIMECOUNTER_H +#define _RTEMS_SCORE_TIMECOUNTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup ScoreTimecounter Timecounter Handler + * + * @ingroup Score + * + * @{ + */ + +/** + * @brief Returns the wall clock time in the bintime format. + * + * @param[out] bt Returns the wall clock time. + */ +void _Timecounter_Bintime( struct bintime *bt ); + +/** + * @brief Returns the wall clock time in the timespec format. + * + * @param[out] ts Returns the wall clock time. + */ +void _Timecounter_Nanotime( struct timespec *ts ); + +/** + * @brief Returns the wall clock time in the timeval format. + * + * @param[out] tv Returns the wall clock time. + */ +void _Timecounter_Microtime( struct timeval *tv ); + +/** + * @brief Returns the uptime in the bintime format. + * + * @param[out] bt Returns the uptime. + */ +void _Timecounter_Binuptime( struct bintime *bt ); + +/** + * @brief Returns the uptime in the timespec format. + * + * @param[out] ts Returns the uptime. + */ +void _Timecounter_Nanouptime( struct timespec *ts ); + +/** + * @brief Returns the uptime in the timeval format. + * + * @param[out] tv Returns the uptime. + */ +void _Timecounter_Microuptime( struct timeval *tv ); + +/** + * @brief Returns the wall clock time in the bintime format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Bintime() variant. + * + * @param[out] ts Returns the wall clock time. + */ +void _Timecounter_Getbintime( struct bintime *bt ); + +/** + * @brief Returns the wall clock time in the timespec format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Nanotime() variant. + * + * @param[out] ts Returns the wall clock time. + * + * @see _Timecounter_Getbintime(). + */ +void _Timecounter_Getnanotime( struct timespec *ts ); + +/** + * @brief Returns the wall clock time in the timeval format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Microtime() variant. + * + * @param[out] tv Returns the wall clock time. + * + * @see _Timecounter_Getbintime(). + */ +void _Timecounter_Getmicrotime( struct timeval *tv ); + +/** + * @brief Returns the uptime in the bintime format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Binuptime() variant. + * + * @param[out] ts Returns the uptime. + */ +void _Timecounter_Getbinuptime( struct bintime *bt ); + +/** + * @brief Returns the uptime in the timespec format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Nanouptime() variant. + * + * @param[out] ts Returns the uptime. + */ +void _Timecounter_Getnanouptime( struct timespec *ts ); + +/** + * @brief Returns the uptime in the timeval format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Microuptime() variant. + * + * @param[out] tv Returns the uptime. + */ +void _Timecounter_Getmicrouptime( struct timeval *tv ); + +/** + * @brief Installs the timecounter. + * + * The timecounter structure must contain valid values in the fields + * tc_get_timecount, tc_counter_mask, tc_frequency and tc_quality. All other + * fields must be zero initialized. + * + * @param[in] tc The timecounter. + */ +void _Timecounter_Install( struct timecounter *tc ); + +/** + * @brief Performs a timecounter tick. + */ +void _Timecounter_Tick( void ); + +/** + * @brief Performs a simple timecounter tick. + * + * This is a special purpose tick function for simple timecounter to support + * legacy clock drivers. + * + * @param[in] delta The time in timecounter ticks elapsed since the last call + * to _Timecounter_Tick_simple(). + * @param[in] offset The current value of the timecounter. + */ +void _Timecounter_Tick_simple( uint32_t delta, uint32_t offset ); + +/** + * @brief The wall clock time in seconds. + */ +extern volatile time_t _Timecounter_Time_second; + +/** + * @brief The uptime in seconds. + * + * For compatibility with the FreeBSD network stack the initial value is one + * second. + */ +extern volatile time_t _Timecounter_Time_uptime; + +/** + * @brief The current timecounter. + */ +extern struct timecounter *_Timecounter; + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_TIMECOUNTER_H */ diff --git a/cpukit/score/include/rtems/score/timecounterimpl.h b/cpukit/score/include/rtems/score/timecounterimpl.h new file mode 100644 index 0000000000..dd47aacc04 --- /dev/null +++ b/cpukit/score/include/rtems/score/timecounterimpl.h @@ -0,0 +1,49 @@ +/** + * @file + * + * @ingroup ScoreTimecounter + * + * @brief Timecounter Implementation + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef _RTEMS_SCORE_TIMECOUNTERIMPL_H +#define _RTEMS_SCORE_TIMECOUNTERIMPL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @addtogroup ScoreTimecounter + * + * @{ + */ + +void _Timecounter_Initialize( void ); + +void _Timecounter_Set_clock( const struct timespec *ts ); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_TIMECOUNTERIMPL_H */ diff --git a/cpukit/score/include/sys/timeffc.h b/cpukit/score/include/sys/timeffc.h index 893afe8bda..b3a1cd9ce7 100644 --- a/cpukit/score/include/sys/timeffc.h +++ b/cpukit/score/include/sys/timeffc.h @@ -55,11 +55,13 @@ struct ffclock_estimate { #if __BSD_VISIBLE #ifdef _KERNEL +#ifndef __rtems__ /* Define the kern.sysclock sysctl tree. */ SYSCTL_DECL(_kern_sysclock); /* Define the kern.sysclock.ffclock sysctl tree. */ SYSCTL_DECL(_kern_sysclock_ffclock); +#endif /* __rtems__ */ /* * Index into the sysclocks array for obtaining the ASCII name of a particular diff --git a/cpukit/score/include/sys/timetc.h b/cpukit/score/include/sys/timetc.h index 9d269a780b..88e90dedac 100644 --- a/cpukit/score/include/sys/timetc.h +++ b/cpukit/score/include/sys/timetc.h @@ -12,9 +12,11 @@ #ifndef _SYS_TIMETC_H_ #define _SYS_TIMETC_H_ +#ifndef __rtems__ #ifndef _KERNEL #error "no user-serviceable parts inside" #endif +#endif /* __rtems__ */ /*- * `struct timecounter' is the interface between the hardware which implements diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 62e15720f4..13ea020c9e 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -13,6 +13,31 @@ all-am: $(PREINSTALL_FILES) PREINSTALL_FILES = CLEANFILES = $(PREINSTALL_FILES) +$(PROJECT_INCLUDE)/sys/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/sys + @: > $(PROJECT_INCLUDE)/sys/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/sys/$(dirstamp) + +$(PROJECT_INCLUDE)/sys/_ffcounter.h: include/sys/_ffcounter.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/_ffcounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/_ffcounter.h + +$(PROJECT_INCLUDE)/sys/timeffc.h: include/sys/timeffc.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timeffc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timeffc.h + +$(PROJECT_INCLUDE)/sys/timepps.h: include/sys/timepps.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timepps.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timepps.h + +$(PROJECT_INCLUDE)/sys/timetc.h: include/sys/timetc.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timetc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timetc.h + +$(PROJECT_INCLUDE)/sys/timex.h: include/sys/timex.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timex.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timex.h + $(PROJECT_INCLUDE)/rtems/$(dirstamp): @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems @: > $(PROJECT_INCLUDE)/rtems/$(dirstamp) @@ -323,6 +348,14 @@ $(PROJECT_INCLUDE)/rtems/score/timestamp64.h: include/rtems/score/timestamp64.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timestamp64.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timestamp64.h +$(PROJECT_INCLUDE)/rtems/score/timecounter.h: include/rtems/score/timecounter.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timecounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timecounter.h + +$(PROJECT_INCLUDE)/rtems/score/timecounterimpl.h: include/rtems/score/timecounterimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timecounterimpl.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timecounterimpl.h + $(PROJECT_INCLUDE)/rtems/score/tls.h: include/rtems/score/tls.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/tls.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/tls.h diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index 246c98bb90..bca73ecb19 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -13,6 +13,27 @@ * of Melbourne under sponsorship from the FreeBSD Foundation. */ +#ifdef __rtems__ +#define _KERNEL +#define bintime _Timecounter_Bintime +#define binuptime _Timecounter_Binuptime +#define boottimebin _Timecounter_Boottimebin +#define getbintime _Timecounter_Getbintime +#define getbinuptime _Timecounter_Getbinuptime +#define getmicrotime _Timecounter_Getmicrotime +#define getmicrouptime _Timecounter_Getmicrouptime +#define getnanotime _Timecounter_Getnanotime +#define getnanouptime _Timecounter_Getnanouptime +#define microtime _Timecounter_Microtime +#define microuptime _Timecounter_Microuptime +#define nanotime _Timecounter_Nanotime +#define nanouptime _Timecounter_Nanouptime +#define tc_init _Timecounter_Install +#define timecounter _Timecounter +#define time_second _Timecounter_Time_second +#define time_uptime _Timecounter_Time_uptime +#include +#endif /* __rtems__ */ #include __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); @@ -21,20 +42,42 @@ __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); #include "opt_ffclock.h" #include +#ifndef __rtems__ #include #include +#else /* __rtems__ */ +#include +#endif /* __rtems__ */ #ifdef FFCLOCK #include #include #endif +#ifndef __rtems__ #include #include #include +#endif /* __rtems__ */ #include #include #include #include +#ifndef __rtems__ #include +#endif /* __rtems__ */ +#ifdef __rtems__ +#include +ISR_LOCK_DEFINE(static, _Timecounter_Lock, "Timecounter"); +#define hz rtems_clock_get_ticks_per_second() +#define printf(...) +#define log(...) +static inline int +fls(int x) +{ + return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; +} +/* FIXME: https://devel.rtems.org/ticket/2348 */ +#define ntp_update_second(a, b) do { (void) a; (void) b; } while (0) +#endif /* __rtems__ */ /* * A large step happens on boot. This constant detects such steps. @@ -53,9 +96,13 @@ __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); static uint32_t dummy_get_timecount(struct timecounter *tc) { +#ifndef __rtems__ static uint32_t now; return (++now); +#else /* __rtems__ */ + return 0; +#endif /* __rtems__ */ } static struct timecounter dummy_timecounter = { @@ -76,6 +123,7 @@ struct timehands { struct timehands *th_next; }; +#if defined(RTEMS_SMP) static struct timehands th0; static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; @@ -86,6 +134,7 @@ static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; +#endif static struct timehands th0 = { &dummy_timecounter, 0, @@ -95,19 +144,26 @@ static struct timehands th0 = { {0, 0}, {0, 0}, 1, +#if defined(RTEMS_SMP) &th1 +#else + &th0 +#endif }; static struct timehands *volatile timehands = &th0; struct timecounter *timecounter = &dummy_timecounter; static struct timecounter *timecounters = &dummy_timecounter; +#ifndef __rtems__ int tc_min_ticktock_freq = 1; +#endif /* __rtems__ */ volatile time_t time_second = 1; volatile time_t time_uptime = 1; struct bintime boottimebin; +#ifndef __rtems__ struct timeval boottime; static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS); SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD, @@ -133,12 +189,16 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation, CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, sysctl_kern_timecounter_adjprecision, "I", "Allowed time interval deviation in percents"); +#endif /* __rtems__ */ static void tc_windup(void); +#ifndef __rtems__ static void cpu_tick_calibrate(int); +#endif /* __rtems__ */ void dtrace_getnanotime(struct timespec *tsp); +#ifndef __rtems__ static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS) { @@ -175,6 +235,7 @@ sysctl_kern_timecounter_freq(SYSCTL_HANDLER_ARGS) freq = tc->tc_frequency; return sysctl_handle_64(oidp, &freq, 0, req); } +#endif /* __rtems__ */ /* * Return the difference between the timehands' counter value now and what @@ -976,6 +1037,7 @@ getmicrotime(struct timeval *tvp) #endif /* FFCLOCK */ +#ifndef __rtems__ /* * This is a clone of getnanotime and used for walltimestamps. * The dtrace_ prefix prevents fbt from creating probes for @@ -993,6 +1055,7 @@ dtrace_getnanotime(struct timespec *tsp) *tsp = th->th_nanotime; } while (gen == 0 || gen != th->th_generation); } +#endif /* __rtems__ */ #ifdef FFCLOCK /* @@ -1006,6 +1069,7 @@ int sysclock_active = SYSCLOCK_FBCK; extern int time_status; extern long time_esterror; +#ifndef __rtems__ /* * Take a snapshot of sysclock data which can be used to compare system clocks * and generate timestamps after the fact. @@ -1137,6 +1201,7 @@ sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, return (0); } +#endif /* __rtems__ */ /* * Initialize a new timecounter and possibly use it. @@ -1144,6 +1209,7 @@ sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, void tc_init(struct timecounter *tc) { +#ifndef __rtems__ uint32_t u; struct sysctl_oid *tc_root; @@ -1163,9 +1229,11 @@ tc_init(struct timecounter *tc) tc->tc_name, (uintmax_t)tc->tc_frequency, tc->tc_quality); } +#endif /* __rtems__ */ tc->tc_next = timecounters; timecounters = tc; +#ifndef __rtems__ /* * Set up sysctl tree for this counter. */ @@ -1196,11 +1264,16 @@ tc_init(struct timecounter *tc) if (tc->tc_quality == timecounter->tc_quality && tc->tc_frequency < timecounter->tc_frequency) return; +#endif /* __rtems__ */ (void)tc->tc_get_timecount(tc); (void)tc->tc_get_timecount(tc); timecounter = tc; +#ifdef __rtems__ + tc_windup(); +#endif /* __rtems__ */ } +#ifndef __rtems__ /* Report the frequency of the current timecounter. */ uint64_t tc_getfrequency(void) @@ -1208,29 +1281,42 @@ tc_getfrequency(void) return (timehands->th_counter->tc_frequency); } +#endif /* __rtems__ */ /* * Step our concept of UTC. This is done by modifying our estimate of * when we booted. * XXX: not locked. */ +#ifndef __rtems__ void tc_setclock(struct timespec *ts) +#else /* __rtems__ */ +void +_Timecounter_Set_clock(const struct timespec *ts) +#endif /* __rtems__ */ { +#ifndef __rtems__ struct timespec tbef, taft; +#endif /* __rtems__ */ struct bintime bt, bt2; +#ifndef __rtems__ cpu_tick_calibrate(1); nanotime(&tbef); +#endif /* __rtems__ */ timespec2bintime(ts, &bt); binuptime(&bt2); bintime_sub(&bt, &bt2); bintime_add(&bt2, &boottimebin); boottimebin = bt; +#ifndef __rtems__ bintime2timeval(&bt, &boottime); +#endif /* __rtems__ */ /* XXX fiddle all the little crinkly bits around the fiords... */ tc_windup(); +#ifndef __rtems__ nanotime(&taft); if (timestepwarnings) { log(LOG_INFO, @@ -1240,6 +1326,7 @@ tc_setclock(struct timespec *ts) (intmax_t)ts->tv_sec, ts->tv_nsec); } cpu_tick_calibrate(1); +#endif /* __rtems__ */ } /* @@ -1256,6 +1343,11 @@ tc_windup(void) uint32_t delta, ncount, ogen; int i; time_t t; +#ifdef __rtems__ + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire(&_Timecounter_Lock, &lock_context); +#endif /* __rtems__ */ /* * Make the next timehands a copy of the current one, but do not @@ -1333,16 +1425,20 @@ tc_windup(void) /* Now is a good time to change timecounters. */ if (th->th_counter != timecounter) { +#ifndef __rtems__ #ifndef __arm__ if ((timecounter->tc_flags & TC_FLAGS_C2STOP) != 0) cpu_disable_c2_sleep++; if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0) cpu_disable_c2_sleep--; #endif +#endif /* __rtems__ */ th->th_counter = timecounter; th->th_offset_count = ncount; +#ifndef __rtems__ tc_min_ticktock_freq = max(1, timecounter->tc_frequency / (((uint64_t)timecounter->tc_counter_mask + 1) / 3)); +#endif /* __rtems__ */ #ifdef FFCLOCK ffclock_change_tc(th); #endif @@ -1401,9 +1497,15 @@ tc_windup(void) #endif timehands = th; +#ifndef __rtems__ timekeep_push_vdso(); +#endif /* __rtems__ */ +#ifdef __rtems__ + _ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, &lock_context); +#endif /* __rtems__ */ } +#ifndef __rtems__ /* Report or change the active timecounter hardware. */ static int sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) @@ -1468,7 +1570,9 @@ sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, sysctl_kern_timecounter_choice, "A", "Timecounter hardware detected"); +#endif /* __rtems__ */ +#ifndef __rtems__ /* * RFC 2783 PPS-API implementation. */ @@ -1749,6 +1853,9 @@ pps_event(struct pps_state *pps, int event) /* Wakeup anyone sleeping in pps_fetch(). */ wakeup(pps); } +#else /* __rtems__ */ +/* FIXME: https://devel.rtems.org/ticket/2349 */ +#endif /* __rtems__ */ /* * Timecounters need to be updated every so often to prevent the hardware @@ -1757,10 +1864,13 @@ pps_event(struct pps_state *pps, int event) * the update frequency. */ +#ifndef __rtems__ static int tc_tick; SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, "Approximate number of hardclock ticks in a millisecond"); +#endif /* __rtems__ */ +#ifndef __rtems__ void tc_ticktock(int cnt) { @@ -1770,9 +1880,54 @@ tc_ticktock(int cnt) if (count < tc_tick) return; count = 0; +#else /* __rtems__ */ +void +_Timecounter_Tick(void) +{ +#endif /* __rtems__ */ tc_windup(); } +#ifdef __rtems__ +void +_Timecounter_Tick_simple(uint32_t delta, uint32_t offset) +{ + struct bintime bt; + struct timehands *th; + uint32_t ogen; + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire(&_Timecounter_Lock, &lock_context); + + th = timehands; + ogen = th->th_generation; + th->th_offset_count = offset; + bintime_addx(&th->th_offset, th->th_scale * delta); + + bt = th->th_offset; + bintime_add(&bt, &boottimebin); + + /* Update the UTC timestamps used by the get*() functions. */ + /* XXX shouldn't do this here. Should force non-`get' versions. */ + bintime2timeval(&bt, &th->th_microtime); + bintime2timespec(&bt, &th->th_nanotime); + + /* + * Now that the struct timehands is again consistent, set the new + * generation number, making sure to not make it zero. + */ + if (++ogen == 0) + ogen = 1; + th->th_generation = ogen; + + /* Go live with the new struct timehands. */ + time_second = th->th_microtime.tv_sec; + time_uptime = th->th_offset.sec; + + _ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, &lock_context); +} +#endif /* __rtems__ */ +#ifndef __rtems__ static void __inline tc_adjprecision(void) { @@ -1794,7 +1949,9 @@ tc_adjprecision(void) sbt_timethreshold = bttosbt(bt_timethreshold); sbt_tickthreshold = bttosbt(bt_tickthreshold); } +#endif /* __rtems__ */ +#ifndef __rtems__ static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS) { @@ -1811,10 +1968,17 @@ sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS) done: return (0); } +#endif /* __rtems__ */ +#ifndef __rtems__ static void inittimecounter(void *dummy) +#else /* __rtems__ */ +void +_Timecounter_Initialize(void) +#endif /* __rtems__ */ { +#ifndef __rtems__ u_int p; int tick_rate; @@ -1838,6 +2002,7 @@ inittimecounter(void *dummy) tc_tick_sbt = bttosbt(tc_tick_bt); p = (tc_tick * 1000000) / hz; printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); +#endif /* __rtems__ */ #ifdef FFCLOCK ffclock_init(); @@ -1848,8 +2013,11 @@ inittimecounter(void *dummy) tc_windup(); } +#ifndef __rtems__ SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); +#endif /* __rtems__ */ +#ifndef __rtems__ /* Cpu tick handling -------------------------------------------------*/ static int cpu_tick_variable; @@ -1982,7 +2150,9 @@ cputick2usec(uint64_t tick) } cpu_tick_f *cpu_ticks = tc_cpu_ticks; +#endif /* __rtems__ */ +#ifndef __rtems__ static int vdso_th_enable = 1; static int sysctl_fast_gettime(SYSCTL_HANDLER_ARGS) @@ -2018,6 +2188,7 @@ tc_fill_vdso_timehands(struct vdso_timehands *vdso_th) enabled = 0; return (enabled); } +#endif /* __rtems__ */ #ifdef COMPAT_FREEBSD32 uint32_t diff --git a/doc/bsp_howto/clock.t b/doc/bsp_howto/clock.t index 396634b067..f58b89850f 100644 --- a/doc/bsp_howto/clock.t +++ b/doc/bsp_howto/clock.t @@ -7,84 +7,282 @@ @section Introduction -The purpose of the clock driver is to provide a steady time -basis to the kernel, so that the RTEMS primitives that need -a clock tick work properly. See the @code{Clock Manager} chapter -of the @b{RTEMS Application C User's Guide} for more details. +The purpose of the clock driver is to provide two services for the operating +system. +@itemize @bullet +@item A steady time basis to the kernel, so that the RTEMS primitives that need +a clock tick work properly. See the @cite{Clock Manager} chapter of the +@cite{RTEMS Application C User's Guide} for more details. +@item An optional time counter to generate timestamps of the uptime and wall +clock time. +@end itemize -The clock driver is located in the @code{clock} directory of the BSP. +The clock driver is usually located in the @file{clock} directory of the BSP. +Clock drivers should use the @dfn{Clock Driver Shell} available via the +@file{clockdrv_shell.h} include file. -@section Clock Driver Global Variables +@section Clock Driver Shell -This section describes the global variables expected to be provided by -this driver. +The @dfn{Clock Driver Shell} include file defines the clock driver functions +declared in @code{#include } which are used by RTEMS +configuration file @code{#include }. In case the application +configuration defines @code{#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER}, +then the clock driver is registered and should provide its services to the +operating system. A hardware specific clock driver must provide some +functions, defines and macros for the @dfn{Clock Driver Shell} which are +explained here step by step. A clock driver file looks in general like this. -@subsection Ticks Counter +@example +/* + * A section with functions, defines and macros to provide hardware specific + * functions for the Clock Driver Shell. + */ + +#include "../../../shared/clockdrv_shell.h" +@end example + +@subsection Initialization + +Depending on the hardware capabilities one out of three clock driver variants +must be selected. +@itemize @bullet +@item The most basic clock driver provides only a periodic interrupt service +routine which calls @code{rtems_clock_tick()}. The interval is determined by +the application configuration via @code{#define +CONFIGURE_MICROSECONDS_PER_TICK} and can be obtained via +@code{rtems_configuration_get_microseconds_per_tick()}. The timestamp +resolution is limited to the clock tick interval. +@item In case the hardware lacks support for a free running counter, then the +module used for the clock tick may provide support for timestamps with a +resolution below the clock tick interval. For this so called simple +timecounters can be used. +@item The desired variant uses a free running counter to provide accurate +timestamps. This variant is mandatory on SMP configurations. +@end itemize -Most of the clock device drivers provide a global variable -that is simply a count of the number of clock driver interrupt service -routines that have occured. This information is valuable when debugging -a system. This variable is declared as follows: +@subsubsection Clock Tick Only Variant @example -volatile uint32_t Clock_driver_ticks; +static void some_support_initialize_hardware( void ) +@{ + /* Initialize hardware */ +@} + +#define Clock_driver_support_initialize_hardware() \ + some_support_initialize_hardware() + +/* Indicate that this clock driver lacks a proper timecounter in hardware */ +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + +#include "../../../shared/clockdrv_shell.h" @end example -@section Initialization +@subsubsection Simple Timecounter Variant + +@example +#include + +static rtems_timecounter_simple some_tc; + +static uint32_t some_tc_get( rtems_timecounter_simple *tc ) +@{ + return some.counter; +@} + +static bool some_tc_is_pending( rtems_timecounter_simple *tc ) +@{ + return some.is_pending; +@} + +static uint32_t some_tc_get_timecount( struct timecounter *tc ) +@{ + return rtems_timecounter_simple_downcounter_get( + tc, + some_tc_get, + some_tc_is_pending + ); +@} + +static void some_tc_tick( void ) +@{ + rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get ); +@} + +static void some_support_initialize_hardware( void ) +@{ + uint32_t frequency = 123456; + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint32_t timecounter_ticks_per_clock_tick = + ( frequency * us_per_tick ) / 1000000; + + /* Initialize hardware */ + + rtems_timecounter_simple_install( + &some_tc, + frequency, + timecounter_ticks_per_clock_tick, + some_tc_get_timecount + ); +@} + +#define Clock_driver_support_initialize_hardware() \ + some_support_initialize_hardware() + +#define Clock_driver_timecounter_tick() \ + some_tc_tick() + +#include "../../../shared/clockdrv_shell.h" +@end example + +@subsubsection Timecounter Variant + +This variant is preferred since it is the most efficient and yields the most +accurate timestamps. It is also mandatory on SMP configurations to obtain +valid timestamps. The hardware must provide a periodic interrupt to service +the clock tick and a free running counter for the timecounter. The free +running counter must have a power of two period. The @code{tc_counter_mask} +must be initialized to the free running counter period minus one, e.g. for a +32-bit counter this is 0xffffffff. The @code{tc_get_timecount} function must +return the current counter value (the counter values must increase, so if the +counter counts down, a conversion is necessary). Use +@code{RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER} for the @code{tc_quality}. Set +@code{tc_frequency} to the frequency of the free running counter in Hz. All +other fields of the @code{struct timecounter} must be zero initialized. +Install the initialized timecounter via @code{rtems_timecounter_install()}. -The initialization routine is responsible for -programming the hardware that will periodically -generate an interrupt. A programmable interval timer is commonly -used as the source of the clock tick. +@example +#include + +static struct timecounter some_tc; + +static uint32_t some_tc_get_timecount( struct timecounter *tc ) +@{ + some.free_running_counter; +@} -The device should be programmed such that an interrupt is generated -every @i{m} microseconds, where @i{m} is equal to -@code{rtems_configuration_get_microseconds_per_tick()}. Sometimes -the periodic interval timer can use a prescaler so you have to look -carefully at your user's manual to determine the correct value. +static void some_support_initialize_hardware( void ) +@{ + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint32_t frequency = 123456; + + /* + * The multiplication must be done in 64-bit arithmetic to avoid an integer + * overflow on targets with a high enough counter frequency. + */ + uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 ); + + /* + * Initialize hardware and set up a periodic interrupt for the configuration + * based interval. + */ + + some_tc.tc_get_timecount = some_tc_get_timecount; + some_tc.tc_counter_mask = 0xffffffff; + some_tc.tc_frequency = frequency; + some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install( &some_tc ); +@} -You must use the RTEMS primitive @code{rtems_interrupt_catch} to install -your clock interrupt service routine: +#define Clock_driver_support_initialize_hardware() \ + some_support_initialize_hardware() + +#include "../../../shared/clockdrv_shell.h" +@end example + +@subsection Install Clock Tick Interrupt Service Routine + +The clock driver must provide a function to install the clock tick interrupt +service routine via @code{Clock_driver_support_install_isr()}. @example -rtems_interrupt_catch (Clock_ISR, CLOCK_VECTOR, &old_handler); +#include +#include + +static void some_support_install_isr( rtems_interrupt_handler isr ) +@{ + rtems_status_code sc; + + sc = rtems_interrupt_handler_install( + SOME_IRQ, + "Clock", + RTEMS_INTERRUPT_UNIQUE, + isr, + NULL + ); + if ( sc != RTEMS_SUCCESSFUL ) @{ + bsp_fatal( SOME_FATAL_IRQ_INSTALL ); + @} +@} + +#define Clock_driver_support_install_isr( isr, old ) \ + some_support_install_isr( isr ) + +#include "../../../shared/clockdrv_shell.h" @end example -Since there is currently not a driver entry point invoked at system -shutdown, many clock device drivers use the @code{atexit} routine -to schedule their @code{Clock_exit} routine to execute when the -system is shutdown. +@subsection Support At Tick -By convention, many of the clock drivers do not install the clock -tick if the @code{ticks_per_timeslice} field of the Configuration -Table is 0. +The hardware specific support at tick is specified by +@code{Clock_driver_support_at_tick()}. -@section System shutdown +@example +static void some_support_at_tick( void ) +@{ + /* Clear interrupt */ +@} -Many drivers provide the routine @code{Clock_exit} that is scheduled -to be run during system shutdown via the @code{atexit} routine. -The @code{Clock_exit} routine will disable the clock tick source -if it was enabled. This can be used to prevent clock ticks after the -system is shutdown. +#define Clock_driver_support_at_tick() \ + some_support_at_tick() -@section Clock Interrupt Subroutine +#include "../../../shared/clockdrv_shell.h" +@end example -It only has to inform the kernel that a ticker has elapsed, so call : +@subsection System Shutdown Support + +The @dfn{Clock Driver Shell} provides the routine @code{Clock_exit()} that is +scheduled to be run during system shutdown via the @code{atexit()} routine. +The hardware specific shutdown support is specified by +@code{Clock_driver_support_shutdown_hardware()} which is used by +@code{Clock_exit()}. It should disable the clock tick source if it was +enabled. This can be used to prevent clock ticks after the system is shutdown. @example -@group -rtems_isr Clock_isr( rtems_vector_number vector ) +static void some_support_shutdown_hardware( void ) @{ - invoke the rtems_clock_tick() directive to announce the tick - if necessary for this hardware - reload the programmable timer + /* Shutdown hardware */ @} -@end group + +#define Clock_driver_support_shutdown_hardware() \ + some_support_shutdown_hardware() + +#include "../../../shared/clockdrv_shell.h" +@end example + +@subsection Multiple Clock Driver Ticks Per Clock Tick + +In case the hardware needs more than one clock driver tick per clock tick (e.g. +due to a limited range of the hardware timer), then this can be specified with +the optional @code{#define CLOCK_DRIVER_ISRS_PER_TICK} and @code{#define +CLOCK_DRIVER_ISRS_PER_TICK_VALUE} defines. This is currently used only for x86 +and it hopefully remains that way. + +@example +/* Enable multiple clock driver ticks per clock tick */ +#define CLOCK_DRIVER_ISRS_PER_TICK 1 + +/* Specifiy the clock driver ticks per clock tick value */ +#define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123 + +#include "../../../shared/clockdrv_shell.h" @end example -@section IO Control +@subsection Clock Driver Ticks Counter -Prior to RTEMS 4.9, the Shared Memory MPCI Driver required a special -IOCTL in the Clock Driver. This is no longer required and the Clock -Driver does not have to provide an IOCTL method at all. +The @dfn{Clock Driver Shell} provide a global variable that is simply a count +of the number of clock driver interrupt service routines that have occurred. +This information is valuable when debugging a system. This variable is +declared as follows: +@example +volatile uint32_t Clock_driver_ticks; +@end example diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 9025ff3535..8844436876 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -38,6 +38,7 @@ else _SUBDIRS += sp29 endif _SUBDIRS += spintrcritical23 +_SUBDIRS += sptimecounter01 _SUBDIRS += spatomic01 _SUBDIRS += spintrcritical22 _SUBDIRS += spsem03 diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index ae3c763848..d463532124 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -41,6 +41,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile spintrcritical23/Makefile +sptimecounter01/Makefile spatomic01/Makefile spglobalcon01/Makefile spintrcritical22/Makefile diff --git a/testsuites/sptests/sptimecounter01/Makefile.am b/testsuites/sptests/sptimecounter01/Makefile.am new file mode 100644 index 0000000000..b2310886fc --- /dev/null +++ b/testsuites/sptests/sptimecounter01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = sptimecounter01 +sptimecounter01_SOURCES = init.c + +dist_rtems_tests_DATA = sptimecounter01.scn sptimecounter01.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 = $(sptimecounter01_OBJECTS) +LINK_LIBS = $(sptimecounter01_LDLIBS) + +sptimecounter01$(EXEEXT): $(sptimecounter01_OBJECTS) $(sptimecounter01_DEPENDENCIES) + @rm -f sptimecounter01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/sptimecounter01/init.c b/testsuites/sptests/sptimecounter01/init.c new file mode 100644 index 0000000000..47ebb2722c --- /dev/null +++ b/testsuites/sptests/sptimecounter01/init.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 + +#include + +#include + +#include +#include +#include +#include + +const char rtems_test_name[] = "SPTIMECOUNTER_1"; + +typedef struct { + struct timecounter tc_soft; + u_int tc_soft_counter; +} test_context; + +static test_context test_instance; + +static uint32_t test_get_timecount_soft(struct timecounter *tc) +{ + test_context *ctx = tc->tc_priv; + + ++ctx->tc_soft_counter; + + return ctx->tc_soft_counter; +} + +void boot_card(const char *cmdline) +{ + test_context *ctx = &test_instance; + struct timecounter *tc_soft = &ctx->tc_soft; + uint64_t soft_freq = 1000000; + struct bintime bt; + + rtems_test_begink(); + + _Timecounter_Initialize(); + _Watchdog_Handler_initialization(); + + rtems_bsd_binuptime(&bt); + assert(bt.sec == 1); + assert(bt.frac== 0); + + rtems_bsd_binuptime(&bt); + assert(bt.sec == 1); + assert(bt.frac == 0); + + rtems_timecounter_tick(); + rtems_bsd_binuptime(&bt); + assert(bt.sec == 1); + assert(bt.frac == 0); + + ctx->tc_soft_counter = 0; + tc_soft->tc_get_timecount = test_get_timecount_soft; + tc_soft->tc_counter_mask = 0x0fffffff; + tc_soft->tc_frequency = soft_freq; + tc_soft->tc_quality = 1234; + tc_soft->tc_priv = ctx; + _Timecounter_Install(tc_soft); + assert(ctx->tc_soft_counter == 3); + + rtems_bsd_binuptime(&bt); + assert(ctx->tc_soft_counter == 4); + + assert(bt.sec == 1); + assert(bt.frac == 18446744073708); + + ctx->tc_soft_counter = 0xf0000000 | 3; + rtems_bsd_binuptime(&bt); + assert(ctx->tc_soft_counter == (0xf0000000 | 4)); + + assert(bt.sec == 1); + assert(bt.frac == 18446744073708); + + /* Ensure that the fraction overflows and the second remains constant */ + ctx->tc_soft_counter = (0xf0000000 | 3) + soft_freq; + rtems_bsd_binuptime(&bt); + assert(ctx->tc_soft_counter == (0xf0000000 | 4) + soft_freq); + assert(bt.sec == 1); + assert(bt.frac == 18446742522092); + + rtems_test_endk(); + + _Terminate(RTEMS_FATAL_SOURCE_EXIT, false, 0); +} + +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_SCHEDULER_USER + +#define CONFIGURE_SCHEDULER_CONTEXT + +#define CONFIGURE_SCHEDULER_CONTROLS { } + +#define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER 0 + +#define CONFIGURE_TASK_STACK_ALLOCATOR NULL + +#define CONFIGURE_TASK_STACK_DEALLOCATOR NULL + +#define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION + +#define CONFIGURE_IDLE_TASK_BODY NULL + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/sptests/sptimecounter01/sptimecounter01.doc b/testsuites/sptests/sptimecounter01/sptimecounter01.doc new file mode 100644 index 0000000000..4a7442c2e6 --- /dev/null +++ b/testsuites/sptests/sptimecounter01/sptimecounter01.doc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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: sptimecounter01 + +directives: + + _Timecounter_Initialize + rtems_timecounter_tick + _Timecounter_Install + rtems_bsd_bintime + +concepts: + + This test checks the correct functioning of the FreeBSD timecounter startup + process diff --git a/testsuites/sptests/sptimecounter01/sptimecounter01.scn b/testsuites/sptests/sptimecounter01/sptimecounter01.scn new file mode 100644 index 0000000000..5fa9c0f281 --- /dev/null +++ b/testsuites/sptests/sptimecounter01/sptimecounter01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SPTIMECOUNTER_1 *** +*** END OF TEST SPTIMECOUNTER_1 *** -- cgit v1.2.3 From 7cd2484c4cf9fc759b7205ed6d8adcc6d2c28ff6 Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Tue, 12 May 2015 14:32:47 +0200 Subject: timecounter: Use in RTEMS Replace timestamp implementation with FreeBSD bintime and timecounters. New test sptests/sptimecounter02. Update #2271. --- cpukit/libnetworking/rtems/rtems_bsdnet_internal.h | 3 +- cpukit/libnetworking/rtems/rtems_glue.c | 4 - cpukit/posix/src/clockgettime.c | 8 +- cpukit/posix/src/posixtimespecabsolutetimeout.c | 2 +- cpukit/posix/src/timergettime.c | 2 +- cpukit/posix/src/timersettime.c | 4 +- cpukit/posix/src/timertsr.c | 2 +- cpukit/rtems/Makefile.am | 2 - cpukit/rtems/include/rtems/rtems/clock.h | 31 +- cpukit/rtems/src/clockgetuptime.c | 2 +- cpukit/rtems/src/clockgetuptimenanoseconds.c | 9 +- cpukit/rtems/src/clockgetuptimeseconds.c | 43 --- cpukit/rtems/src/clockgetuptimetimeval.c | 2 +- cpukit/rtems/src/clocksetnsecshandler.c | 34 -- cpukit/rtems/src/clocktick.c | 17 +- cpukit/sapi/src/exinit.c | 1 + cpukit/score/Makefile.am | 16 +- cpukit/score/include/rtems/score/timespec.h | 6 +- cpukit/score/include/rtems/score/timestamp.h | 253 ++++++++------ cpukit/score/include/rtems/score/timestamp64.h | 379 --------------------- cpukit/score/include/rtems/score/tod.h | 9 - cpukit/score/include/rtems/score/todimpl.h | 135 ++++---- cpukit/score/include/rtems/score/watchdogimpl.h | 7 + cpukit/score/preinstall.am | 4 - cpukit/score/src/coretod.c | 20 +- cpukit/score/src/coretodadjust.c | 9 +- cpukit/score/src/coretodget.c | 46 --- cpukit/score/src/coretodgetuptimetimespec.c | 32 -- cpukit/score/src/coretodsecondssinceepoch.c | 32 -- cpukit/score/src/coretodset.c | 19 +- cpukit/score/src/coretodtickle.c | 22 +- cpukit/score/src/kern_tc.c | 6 + cpukit/score/src/timespecgetasnanoseconds.c | 7 +- cpukit/score/src/ts64addto.c | 31 -- cpukit/score/src/ts64divide.c | 51 --- cpukit/score/src/ts64equalto.c | 31 -- cpukit/score/src/ts64getnanoseconds.c | 30 -- cpukit/score/src/ts64getseconds.c | 30 -- cpukit/score/src/ts64lessthan.c | 31 -- cpukit/score/src/ts64set.c | 33 -- cpukit/score/src/ts64settozero.c | 31 -- cpukit/score/src/ts64subtract.c | 31 -- cpukit/score/src/ts64totimespec.c | 32 -- cpukit/score/src/ts64totimeval.c | 37 -- cpukit/score/src/watchdogtick.c | 34 ++ testsuites/sptests/Makefile.am | 1 + testsuites/sptests/configure.ac | 1 + testsuites/sptests/spclock_err01/init.c | 8 - testsuites/sptests/spsize/size.c | 3 - testsuites/sptests/sptimecounter02/Makefile.am | 20 ++ testsuites/sptests/sptimecounter02/init.c | 268 +++++++++++++++ .../sptests/sptimecounter02/sptimecounter02.doc | 12 + .../sptests/sptimecounter02/sptimecounter02.scn | 46 +++ 53 files changed, 652 insertions(+), 1277 deletions(-) delete mode 100644 cpukit/rtems/src/clockgetuptimeseconds.c delete mode 100644 cpukit/rtems/src/clocksetnsecshandler.c delete mode 100644 cpukit/score/include/rtems/score/timestamp64.h delete mode 100644 cpukit/score/src/coretodget.c delete mode 100644 cpukit/score/src/coretodgetuptimetimespec.c delete mode 100644 cpukit/score/src/coretodsecondssinceepoch.c delete mode 100644 cpukit/score/src/ts64addto.c delete mode 100644 cpukit/score/src/ts64divide.c delete mode 100644 cpukit/score/src/ts64equalto.c delete mode 100644 cpukit/score/src/ts64getnanoseconds.c delete mode 100644 cpukit/score/src/ts64getseconds.c delete mode 100644 cpukit/score/src/ts64lessthan.c delete mode 100644 cpukit/score/src/ts64set.c delete mode 100644 cpukit/score/src/ts64settozero.c delete mode 100644 cpukit/score/src/ts64subtract.c delete mode 100644 cpukit/score/src/ts64totimespec.c delete mode 100644 cpukit/score/src/ts64totimeval.c create mode 100644 cpukit/score/src/watchdogtick.c create mode 100644 testsuites/sptests/sptimecounter02/Makefile.am create mode 100644 testsuites/sptests/sptimecounter02/init.c create mode 100644 testsuites/sptests/sptimecounter02/sptimecounter02.doc create mode 100644 testsuites/sptests/sptimecounter02/sptimecounter02.scn diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h index fc0370ceb5..4de1b0bda6 100644 --- a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h +++ b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h @@ -12,6 +12,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -61,7 +62,7 @@ void *memset(void *s, int c, size_t n); #define panic rtems_panic #define suser(a,b) 0 -void microtime(struct timeval *tv); +#define microtime(tv) rtems_bsd_microtime(tv) #define hz rtems_bsdnet_ticks_per_second #define tick rtems_bsdnet_microseconds_per_tick diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index e43dc6e1dc..1355fbb838 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -1339,7 +1339,3 @@ m_clalloc(int ncl, int nowait) return 1; } -void microtime(struct timeval *tv) -{ - rtems_clock_get_uptime_timeval(tv); -} diff --git a/cpukit/posix/src/clockgettime.c b/cpukit/posix/src/clockgettime.c index 2838ba657e..83a35d769a 100644 --- a/cpukit/posix/src/clockgettime.c +++ b/cpukit/posix/src/clockgettime.c @@ -37,19 +37,21 @@ int clock_gettime( rtems_set_errno_and_return_minus_one( EINVAL ); if ( clock_id == CLOCK_REALTIME ) { - _TOD_Get(tp); + _TOD_Get_as_timespec(tp); return 0; } #ifdef CLOCK_MONOTONIC if ( clock_id == CLOCK_MONOTONIC ) { - _TOD_Get_uptime_as_timespec( tp ); + _TOD_Get_zero_based_uptime_as_timespec( tp ); + --tp->tv_sec; return 0; } #endif #ifdef _POSIX_CPUTIME if ( clock_id == CLOCK_PROCESS_CPUTIME_ID ) { - _TOD_Get_uptime_as_timespec( tp ); + _TOD_Get_zero_based_uptime_as_timespec( tp ); + --tp->tv_sec; return 0; } #endif diff --git a/cpukit/posix/src/posixtimespecabsolutetimeout.c b/cpukit/posix/src/posixtimespecabsolutetimeout.c index 32da45f3ae..f3029861d1 100644 --- a/cpukit/posix/src/posixtimespecabsolutetimeout.c +++ b/cpukit/posix/src/posixtimespecabsolutetimeout.c @@ -57,7 +57,7 @@ POSIX_Absolute_timeout_conversion_results_t _POSIX_Absolute_timeout_to_ticks( /* * Is the absolute time in the past? */ - _TOD_Get( ¤t_time ); + _TOD_Get_as_timespec( ¤t_time ); if ( _Timespec_Less_than( abstime, ¤t_time ) ) return POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST; diff --git a/cpukit/posix/src/timergettime.c b/cpukit/posix/src/timergettime.c index 2a810ef42d..f065cc927c 100644 --- a/cpukit/posix/src/timergettime.c +++ b/cpukit/posix/src/timergettime.c @@ -49,7 +49,7 @@ int timer_gettime( rtems_set_errno_and_return_minus_one( EINVAL ); /* Reads the current time */ - _TOD_Get( ¤t_time ); + _TOD_Get_as_timespec( ¤t_time ); ptimer = _POSIX_Timer_Get( timerid, &location ); switch ( location ) { diff --git a/cpukit/posix/src/timersettime.c b/cpukit/posix/src/timersettime.c index 2967df6df0..2a8cec7652 100644 --- a/cpukit/posix/src/timersettime.c +++ b/cpukit/posix/src/timersettime.c @@ -66,7 +66,7 @@ int timer_settime( /* Convert absolute to relative time */ if (flags == TIMER_ABSTIME) { struct timespec now; - _TOD_Get( &now ); + _TOD_Get_as_timespec( &now ); /* Check for seconds in the past */ if ( _Timespec_Greater_than( &now, &normalize.it_value ) ) rtems_set_errno_and_return_minus_one( EINVAL ); @@ -125,7 +125,7 @@ int timer_settime( /* Indicate that the time is running */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; - _TOD_Get( &ptimer->time ); + _TOD_Get_as_timespec( &ptimer->time ); _Objects_Put( &ptimer->Object ); return 0; diff --git a/cpukit/posix/src/timertsr.c b/cpukit/posix/src/timertsr.c index 85554633e9..512dd06d38 100644 --- a/cpukit/posix/src/timertsr.c +++ b/cpukit/posix/src/timertsr.c @@ -58,7 +58,7 @@ void _POSIX_Timer_TSR( return; /* Store the time when the timer was started again */ - _TOD_Get( &ptimer->time ); + _TOD_Get_as_timespec( &ptimer->time ); /* The state really did not change but just to be safe */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; diff --git a/cpukit/rtems/Makefile.am b/cpukit/rtems/Makefile.am index 084b39f8b3..f38990d2a7 100644 --- a/cpukit/rtems/Makefile.am +++ b/cpukit/rtems/Makefile.am @@ -155,10 +155,8 @@ librtems_a_SOURCES += src/clockgettod.c librtems_a_SOURCES += src/clockgettodtimeval.c librtems_a_SOURCES += src/clockgetuptime.c librtems_a_SOURCES += src/clockgetuptimetimeval.c -librtems_a_SOURCES += src/clockgetuptimeseconds.c librtems_a_SOURCES += src/clockgetuptimenanoseconds.c librtems_a_SOURCES += src/clockset.c -librtems_a_SOURCES += src/clocksetnsecshandler.c librtems_a_SOURCES += src/clocktick.c librtems_a_SOURCES += src/clocktodtoseconds.c librtems_a_SOURCES += src/clocktodvalidate.c diff --git a/cpukit/rtems/include/rtems/rtems/clock.h b/cpukit/rtems/include/rtems/rtems/clock.h index 2a1c77251f..989bf2f5c9 100644 --- a/cpukit/rtems/include/rtems/rtems/clock.h +++ b/cpukit/rtems/include/rtems/rtems/clock.h @@ -14,7 +14,6 @@ * * - set the current date and time * - obtain the current date and time - * - set the nanoseconds since last clock tick handler * - announce a clock tick * - obtain the system uptime */ @@ -35,6 +34,7 @@ #include #include #include +#include #include /* struct timeval */ @@ -68,12 +68,6 @@ typedef enum { RTEMS_CLOCK_GET_TIME_VALUE } rtems_clock_get_options; -/** - * Type for the nanoseconds since last tick BSP extension. - */ -typedef TOD_Nanoseconds_since_last_tick_routine - rtems_nanoseconds_extension_routine; - /** * @brief Obtain Current Time of Day * @@ -278,24 +272,6 @@ rtems_status_code rtems_clock_set( */ rtems_status_code rtems_clock_tick( void ); -/** - * @brief Set the BSP specific Nanoseconds Extension - * - * Clock Manager - * - * This directive sets the BSP provided nanoseconds since last tick - * extension. - * - * @param[in] routine is a pointer to the extension routine - * - * @return This method returns RTEMS_SUCCESSFUL if there was not an - * error. Otherwise, a status code is returned indicating the - * source of the error. - */ -rtems_status_code rtems_clock_set_nanoseconds_extension( - rtems_nanoseconds_extension_routine routine -); - /** * @brief Obtain the System Uptime * @@ -328,7 +304,10 @@ void rtems_clock_get_uptime_timeval( struct timeval *uptime ); * * @retval The system uptime in seconds. */ -time_t rtems_clock_get_uptime_seconds( void ); +RTEMS_INLINE_ROUTINE time_t rtems_clock_get_uptime_seconds( void ) +{ + return _Timecounter_Time_uptime - 1; +} /** * @brief Returns the system uptime in nanoseconds. diff --git a/cpukit/rtems/src/clockgetuptime.c b/cpukit/rtems/src/clockgetuptime.c index 91ce6c46ee..acbe39a00e 100644 --- a/cpukit/rtems/src/clockgetuptime.c +++ b/cpukit/rtems/src/clockgetuptime.c @@ -42,6 +42,6 @@ rtems_status_code rtems_clock_get_uptime( if ( !uptime ) return RTEMS_INVALID_ADDRESS; - _TOD_Get_uptime_as_timespec( uptime ); + _TOD_Get_zero_based_uptime_as_timespec( uptime ); return RTEMS_SUCCESSFUL; } diff --git a/cpukit/rtems/src/clockgetuptimenanoseconds.c b/cpukit/rtems/src/clockgetuptimenanoseconds.c index 0310e592e9..03ff73bba3 100644 --- a/cpukit/rtems/src/clockgetuptimenanoseconds.c +++ b/cpukit/rtems/src/clockgetuptimenanoseconds.c @@ -23,13 +23,8 @@ uint64_t rtems_clock_get_uptime_nanoseconds( void ) { Timestamp_Control snapshot_as_timestamp; - uint32_t nanoseconds; - ISR_lock_Context lock_context; - _TOD_Acquire( &_TOD, &lock_context ); - snapshot_as_timestamp = _TOD.uptime; - nanoseconds = ( *_TOD.nanoseconds_since_last_tick )(); - _TOD_Release( &_TOD, &lock_context ); + _TOD_Get_zero_based_uptime(&snapshot_as_timestamp); - return _Timestamp_Get_As_nanoseconds( &snapshot_as_timestamp, nanoseconds ); + return _Timestamp_Get_as_nanoseconds(&snapshot_as_timestamp); } diff --git a/cpukit/rtems/src/clockgetuptimeseconds.c b/cpukit/rtems/src/clockgetuptimeseconds.c deleted file mode 100644 index 0312921113..0000000000 --- a/cpukit/rtems/src/clockgetuptimeseconds.c +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file - * - * @brief Returns the system uptime in seconds. - * @ingroup ClassicClock Clocks - */ - -/* - * Copyright (c) 2012 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H - #include "config.h" -#endif - -#include -#include - -time_t rtems_clock_get_uptime_seconds( void ) -{ - TOD_Control *tod = &_TOD; - Timestamp_Control snapshot_as_timestamp; - struct timespec snapshot_as_timespec; - ISR_lock_Context lock_context; - - _TOD_Acquire( tod, &lock_context ); - snapshot_as_timestamp = tod->uptime; - _TOD_Release( tod, &lock_context ); - - _Timestamp_To_timespec( &snapshot_as_timestamp, &snapshot_as_timespec ); - - return snapshot_as_timespec.tv_sec; -} diff --git a/cpukit/rtems/src/clockgetuptimetimeval.c b/cpukit/rtems/src/clockgetuptimetimeval.c index 0cbaa836bc..2e09ae2cd2 100644 --- a/cpukit/rtems/src/clockgetuptimetimeval.c +++ b/cpukit/rtems/src/clockgetuptimetimeval.c @@ -30,6 +30,6 @@ void rtems_clock_get_uptime_timeval( struct timeval *uptime ) { Timestamp_Control snapshot_as_timestamp; - _TOD_Get_uptime( &snapshot_as_timestamp ); + _TOD_Get_zero_based_uptime( &snapshot_as_timestamp ); _Timestamp_To_timeval( &snapshot_as_timestamp, uptime ); } diff --git a/cpukit/rtems/src/clocksetnsecshandler.c b/cpukit/rtems/src/clocksetnsecshandler.c deleted file mode 100644 index ae08246902..0000000000 --- a/cpukit/rtems/src/clocksetnsecshandler.c +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @file - * - * @brief Set the BSP specific Nanoseconds Extension - * @ingroup ClassicClock Clocks - */ - -/* - * COPYRIGHT (c) 1989-2006. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -rtems_status_code rtems_clock_set_nanoseconds_extension( - rtems_nanoseconds_extension_routine routine -) -{ - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - _TOD_Set_nanoseconds_since_last_tick_handler( routine ); - - return RTEMS_SUCCESSFUL; -} diff --git a/cpukit/rtems/src/clocktick.c b/cpukit/rtems/src/clocktick.c index fe49e9a059..e2cd35f5fc 100644 --- a/cpukit/rtems/src/clocktick.c +++ b/cpukit/rtems/src/clocktick.c @@ -19,21 +19,14 @@ #endif #include -#include -#include -#include -#include +#include rtems_status_code rtems_clock_tick( void ) { - _TOD_Tickle_ticks(); - - _Watchdog_Tickle_ticks(); - - _Scheduler_Tick(); - - if ( _Thread_Dispatch_is_enabled() ) - _Thread_Dispatch(); + _Timecounter_Tick_simple( + rtems_configuration_get_microseconds_per_tick(), + 0 + ); return RTEMS_SUCCESSFUL; } diff --git a/cpukit/sapi/src/exinit.c b/cpukit/sapi/src/exinit.c index ba71ec465b..31158995ab 100644 --- a/cpukit/sapi/src/exinit.c +++ b/cpukit/sapi/src/exinit.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index a16aedac1d..11399e9c73 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -93,7 +93,6 @@ include_rtems_score_HEADERS += include/rtems/score/threadq.h include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h include_rtems_score_HEADERS += include/rtems/score/timespec.h include_rtems_score_HEADERS += include/rtems/score/timestamp.h -include_rtems_score_HEADERS += include/rtems/score/timestamp64.h include_rtems_score_HEADERS += include/rtems/score/timecounter.h include_rtems_score_HEADERS += include/rtems/score/timecounterimpl.h include_rtems_score_HEADERS += include/rtems/score/tls.h @@ -320,23 +319,16 @@ libscore_a_SOURCES += src/timespecaddto.c src/timespecfromticks.c \ src/timespecsubtract.c src/timespectoticks.c src/timespecdivide.c \ src/timespecdividebyinteger.c src/timespecgetasnanoseconds.c -## TIMESTAMP_INT64_C_FILES -libscore_a_SOURCES += src/ts64addto.c \ - src/ts64divide.c src/ts64equalto.c \ - src/ts64getnanoseconds.c src/ts64getseconds.c \ - src/ts64lessthan.c \ - src/ts64set.c src/ts64settozero.c src/ts64subtract.c \ - src/ts64totimespec.c src/ts64totimeval.c - ## TOD_C_FILES -libscore_a_SOURCES += src/coretod.c src/coretodset.c src/coretodget.c \ - src/coretodgetuptimetimespec.c src/coretodtickle.c \ - src/coretodsecondssinceepoch.c src/coretodtickspersec.c \ +libscore_a_SOURCES += src/coretod.c src/coretodset.c \ + src/coretodtickle.c \ + src/coretodtickspersec.c \ src/coretodadjust.c ## WATCHDOG_C_FILES libscore_a_SOURCES += src/watchdog.c src/watchdogadjust.c \ src/watchdoginsert.c src/watchdogremove.c +libscore_a_SOURCES += src/watchdogtick.c libscore_a_SOURCES += src/watchdogtickssinceboot.c ## USEREXT_C_FILES diff --git a/cpukit/score/include/rtems/score/timespec.h b/cpukit/score/include/rtems/score/timespec.h index 9200880222..72a000177f 100644 --- a/cpukit/score/include/rtems/score/timespec.h +++ b/cpukit/score/include/rtems/score/timespec.h @@ -94,13 +94,11 @@ extern "C" { * This method returns the timestamp as nanoseconds. * * @param[in] time points to the timestamp. - * @param[in] nanoseconds the nanoseconds since the last tick. * * @retval The time in nanoseconds. */ -uint64_t _Timespec_Get_As_nanoseconds( - const struct timespec *time, - const uint32_t nanoseconds +uint64_t _Timespec_Get_as_nanoseconds( + const struct timespec *time ); /** diff --git a/cpukit/score/include/rtems/score/timestamp.h b/cpukit/score/include/rtems/score/timestamp.h index dbd0425ff8..9d25943a8c 100644 --- a/cpukit/score/include/rtems/score/timestamp.h +++ b/cpukit/score/include/rtems/score/timestamp.h @@ -42,37 +42,17 @@ #include -#include +#include #include #ifdef __cplusplus extern "C" { #endif -#if ! ( ( CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE \ - && CPU_TIMESTAMP_USE_INT64 == FALSE \ - && CPU_TIMESTAMP_USE_INT64_INLINE == FALSE ) \ - || ( CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == FALSE \ - && CPU_TIMESTAMP_USE_INT64 == TRUE \ - && CPU_TIMESTAMP_USE_INT64_INLINE == FALSE ) \ - || ( CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == FALSE \ - && CPU_TIMESTAMP_USE_INT64 == FALSE \ - && CPU_TIMESTAMP_USE_INT64_INLINE == TRUE ) ) - #error "Invalid SuperCore Timestamp implementations selection." -#endif - -#if CPU_TIMESTAMP_USE_INT64 == TRUE || CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #include -#endif - /** * Define the Timestamp control type. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - typedef struct timespec Timestamp_Control; -#else - typedef Timestamp64_Control Timestamp_Control; -#endif +typedef struct bintime Timestamp_Control; /** * @brief Set timestamp to specified seconds and nanoseconds. @@ -84,13 +64,19 @@ extern "C" { * @param[in] _seconds is the seconds portion of the timestamp * @param[in] _nanoseconds is the nanoseconds portion of the timestamp */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Set( _time, _seconds, _nanoseconds ) \ - _Timespec_Set( _time, _seconds, _nanoseconds ) -#else - #define _Timestamp_Set( _time, _seconds, _nanoseconds ) \ - _Timestamp64_Set( _time, _seconds, _nanoseconds ) -#endif +RTEMS_INLINE_ROUTINE void _Timestamp_Set( + Timestamp_Control *_time, + time_t _seconds, + long _nanoseconds +) +{ + struct timespec _ts; + + _ts.tv_sec = _seconds; + _ts.tv_nsec = _nanoseconds; + + timespec2bintime( &_ts, _time ); +} /** * @brief Sets the timestamp to zero. @@ -100,13 +86,14 @@ extern "C" { * * @param[in] _time points to the timestamp instance to zero. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Set_to_zero( _time ) \ - _Timespec_Set_to_zero( _time ) -#else - #define _Timestamp_Set_to_zero( _time ) \ - _Timestamp64_Set_to_zero( _time ) -#endif + +RTEMS_INLINE_ROUTINE void _Timestamp_Set_to_zero( + Timestamp_Control *_time +) +{ + _time->sec = 0; + _time->frac = 0; +} /** * @brief Less than operator for timestamps. @@ -119,13 +106,20 @@ extern "C" { * @retval This method returns true if @a _lhs is less than the @a _rhs and * false otherwise. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Less_than( _lhs, _rhs ) \ - _Timespec_Less_than( _lhs, _rhs ) -#else - #define _Timestamp_Less_than( _lhs, _rhs ) \ - _Timestamp64_Less_than( _lhs, _rhs ) -#endif + +RTEMS_INLINE_ROUTINE bool _Timestamp_Less_than( + const Timestamp_Control *_lhs, + const Timestamp_Control *_rhs +) +{ + if ( _lhs->sec < _rhs->sec ) + return true; + + if ( _lhs->sec > _rhs->sec ) + return false; + + return _lhs->frac < _rhs->frac; +} /** * @brief Greater than operator for timestamps. @@ -138,8 +132,20 @@ extern "C" { * @retval This method returns true if @a _lhs is greater than the @a _rhs and * false otherwise. */ -#define _Timestamp_Greater_than( _lhs, _rhs ) \ - _Timestamp_Less_than( _rhs, _lhs ) + +RTEMS_INLINE_ROUTINE bool _Timestamp_Greater_than( + const Timestamp_Control *_lhs, + const Timestamp_Control *_rhs +) +{ + if ( _lhs->sec > _rhs->sec ) + return true; + + if ( _lhs->sec < _rhs->sec ) + return false; + + return _lhs->frac > _rhs->frac; +} /** * @brief Equal to than operator for timestamps. @@ -152,13 +158,14 @@ extern "C" { * @retval This method returns true if @a _lhs is equal to @a _rhs and * false otherwise. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Equal_to( _lhs, _rhs ) \ - _Timespec_Equal_to( _lhs, _rhs ) -#else - #define _Timestamp_Equal_to( _lhs, _rhs ) \ - _Timestamp64_Equal_to( _lhs, _rhs ) -#endif + +RTEMS_INLINE_ROUTINE bool _Timestamp_Equal_to( + const Timestamp_Control *_lhs, + const Timestamp_Control *_rhs +) +{ + return _lhs->sec == _rhs->sec && _lhs->frac == _rhs->frac; +} /** * @brief Adds two timestamps. @@ -171,13 +178,17 @@ extern "C" { * * @retval This method returns the number of seconds @a time increased by. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Add_to( _time, _add ) \ - _Timespec_Add_to( _time, _add ) -#else - #define _Timestamp_Add_to( _time, _add ) \ - _Timestamp64_Add_to( _time, _add ) -#endif +RTEMS_INLINE_ROUTINE time_t _Timestamp_Add_to( + Timestamp_Control *_time, + const Timestamp_Control *_add +) +{ + time_t seconds = _time->sec; + + bintime_add( _time, _add ); + + return _time->sec - seconds; +} /** * @brief Subtracts two timestamps. @@ -192,13 +203,17 @@ extern "C" { * * @retval This method fills in @a _result. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Subtract( _start, _end, _result ) \ - _Timespec_Subtract( _start, _end, _result ) -#else - #define _Timestamp_Subtract( _start, _end, _result ) \ - _Timestamp64_Subtract( _start, _end, _result ) -#endif +RTEMS_INLINE_ROUTINE void _Timestamp_Subtract( + const Timestamp_Control *_start, + const Timestamp_Control *_end, + Timestamp_Control *_result +) +{ + _result->sec = _end->sec; + _result->frac = _end->frac; + + bintime_sub( _result, _start ); +} /** * @brief Divides a timestamp by another timestamp. @@ -213,13 +228,26 @@ extern "C" { * * @retval This method fills in @a result. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Divide( _lhs, _rhs, _ival_percentage, _fval_percentage ) \ - _Timespec_Divide( _lhs, _rhs, _ival_percentage, _fval_percentage ) -#else - #define _Timestamp_Divide( _lhs, _rhs, _ival_percentage, _fval_percentage ) \ - _Timestamp64_Divide( _lhs, _rhs, _ival_percentage, _fval_percentage ) -#endif +RTEMS_INLINE_ROUTINE void _Timestamp_Divide( + const Timestamp_Control *_lhs, + const Timestamp_Control *_rhs, + uint32_t *_ival_percentage, + uint32_t *_fval_percentage +) +{ + struct timespec _ts_left; + struct timespec _ts_right; + + bintime2timespec( _lhs, &_ts_left ); + bintime2timespec( _rhs, &_ts_right ); + + _Timespec_Divide( + &_ts_left, + &_ts_right, + _ival_percentage, + _fval_percentage + ); +} /** * @brief Get seconds portion of timestamp. @@ -230,13 +258,12 @@ extern "C" { * * @retval The seconds portion of @a _time. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Get_seconds( _time ) \ - _Timespec_Get_seconds( _time ) -#else - #define _Timestamp_Get_seconds( _time ) \ - _Timestamp64_Get_seconds( _time ) -#endif +RTEMS_INLINE_ROUTINE time_t _Timestamp_Get_seconds( + const Timestamp_Control *_time +) +{ + return _time->sec; +} /** * @brief Get nanoseconds portion of timestamp. @@ -247,13 +274,16 @@ extern "C" { * * @retval The nanoseconds portion of @a _time. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Get_nanoseconds( _time ) \ - _Timespec_Get_nanoseconds( _time ) -#else - #define _Timestamp_Get_nanoseconds( _time ) \ - _Timestamp64_Get_nanoseconds( _time ) -#endif +RTEMS_INLINE_ROUTINE uint32_t _Timestamp_Get_nanoseconds( + const Timestamp_Control *_time +) +{ + struct timespec _ts; + + bintime2timespec( _time, &_ts ); + + return _ts.tv_nsec; +} /** * @brief Get the timestamp as nanoseconds. @@ -264,13 +294,16 @@ extern "C" { * * @retval The time in nanoseconds. */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_Get_As_nanoseconds( _timestamp, _nanoseconds ) \ - _Timespec_Get_As_nanoseconds( _timestamp, _nanoseconds ) -#else - #define _Timestamp_Get_As_nanoseconds( _timestamp, _nanoseconds ) \ - _Timestamp64_Get_As_nanoseconds( _timestamp, _nanoseconds ) -#endif +RTEMS_INLINE_ROUTINE uint64_t _Timestamp_Get_as_nanoseconds( + const Timestamp_Control *_time +) +{ + struct timespec _ts; + + bintime2timespec( _time, &_ts ); + + return _Timespec_Get_as_nanoseconds( &_ts ); +} /** * @brief Convert timestamp to struct timespec. @@ -280,14 +313,13 @@ extern "C" { * @param[in] _timestamp points to the timestamp * @param[in] _timespec points to the timespec */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - /* in this case we know they are the same type so use simple assignment */ - #define _Timestamp_To_timespec( _timestamp, _timespec ) \ - *(_timespec) = *(_timestamp) -#else - #define _Timestamp_To_timespec( _timestamp, _timespec ) \ - _Timestamp64_To_timespec( _timestamp, _timespec ) -#endif +RTEMS_INLINE_ROUTINE void _Timestamp_To_timespec( + const Timestamp_Control *_timestamp, + struct timespec *_timespec +) +{ + bintime2timespec( _timestamp, _timespec ); +} /** * @brief Convert timestamp to struct timeval. @@ -295,16 +327,13 @@ extern "C" { * @param[in] _timestamp points to the timestamp * @param[in] _timeval points to the timeval */ -#if CPU_TIMESTAMP_USE_STRUCT_TIMESPEC == TRUE - #define _Timestamp_To_timeval( _timestamp, _timeval ) \ - do { \ - (_timeval)->tv_sec = (_timestamp)->tv_sec; \ - (_timeval)->tv_usec = (_timestamp)->tv_nsec / 1000; \ - } while (0) -#else - #define _Timestamp_To_timeval( _timestamp, _timeval ) \ - _Timestamp64_To_timeval( _timestamp, _timeval ) -#endif +RTEMS_INLINE_ROUTINE void _Timestamp_To_timeval( + const Timestamp_Control *_timestamp, + struct timeval *_timeval +) +{ + bintime2timeval( _timestamp, _timeval ); +} #ifdef __cplusplus } diff --git a/cpukit/score/include/rtems/score/timestamp64.h b/cpukit/score/include/rtems/score/timestamp64.h deleted file mode 100644 index 39b4965a8c..0000000000 --- a/cpukit/score/include/rtems/score/timestamp64.h +++ /dev/null @@ -1,379 +0,0 @@ -/** - * @file rtems/score/timestamp64.h - * - * @brief Helpers for Manipulating 64-bit Integer Timestamps - * - * This include file contains helpers for manipulating - * 64-bit integer timestamps. - */ - -/* - * COPYRIGHT (c) 1989-2009. - * 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. - */ - -#ifndef _RTEMS_SCORE_TIMESTAMP64_H -#define _RTEMS_SCORE_TIMESTAMP64_H - -/** - * @defgroup SuperCoreTimestamp64 SuperCore Sixty-Four Bit Timestamps - * - * @ingroup Score - * - * This handler encapsulates functionality related to manipulating - * the 64 bit integer implementation of SuperCore Timestamps. - */ -/**@{*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This .h file is not for general use. It is an alternative - * implementation of Timestamps and should only be used that way. - */ -#ifndef _RTEMS_SCORE_TIMESTAMP_H - #error "Should only be included by rtems/score/timestamp.h" -#endif - -/* - * Verify something is defined. - */ -#if CPU_TIMESTAMP_USE_INT64 != TRUE && CPU_TIMESTAMP_USE_INT64_INLINE != TRUE - #error "SuperCore Timestamp64 implementation included but not defined." -#endif - -/** - * Define the Timestamp control type. - */ -typedef int64_t Timestamp64_Control; - -static inline void _Timestamp64_implementation_Set( - Timestamp64_Control *_time, - Timestamp64_Control _seconds, - Timestamp64_Control _nanoseconds -) -{ - *_time = _seconds * 1000000000L + _nanoseconds; -} - -/** - * @brief Set 64-bit timestamp to seconds nanosecond. - * - * This method sets the timestamp to the specified seconds and nanoseconds - * value. - * - * @param[in] _time points to the timestamp instance to validate. - * @param[in] _seconds is the seconds portion of the timestamp - * @param[in] _nanoseconds is the nanoseconds portion of the timestamp - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Set( _time, _seconds, _nanoseconds ) \ - _Timestamp64_implementation_Set( _time, _seconds, _nanoseconds ) -#else - void _Timestamp64_Set( - Timestamp64_Control *_time, - Timestamp64_Control _seconds, - Timestamp64_Control _nanoseconds - ); -#endif - -static inline void _Timestamp64_implementation_Set_to_zero( - Timestamp64_Control *_time -) -{ - *_time = 0; -} - -/** - * @brief Sets the 64-bit timestamp to zero. - * - * This method sets the timestamp to zero value. - * - * @param[in] _time points to the timestamp instance to zero. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Set_to_zero( _time ) \ - _Timestamp64_implementation_Set_to_zero( _time ) -#else - void _Timestamp64_Set_to_zero( - Timestamp64_Control *_time - ); -#endif - -static inline bool _Timestamp64_implementation_Less_than( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs -) -{ - return *_lhs < *_rhs; -} - -/** - * @brief The "less than" operator for 64-bit timestamps. - * - * This method is the less than operator for timestamps. - * - * @param[in] _lhs points to the left hand side timestamp - * @param[in] _rhs points to the right hand side timestamp - * - * @retval This method returns true if @a _lhs is less than the @a _rhs and - * false otherwise. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Less_than( _lhs, _rhs ) \ - _Timestamp64_implementation_Less_than( _lhs, _rhs ) -#else - bool _Timestamp64_Less_than( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs - ); -#endif - -static inline bool _Timestamp64_implementation_Equal_to( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs -) -{ - return *_lhs == *_rhs; -} - -#define _Timestamp64_Greater_than( _lhs, _rhs ) \ - _Timestamp64_Less_than( _rhs, _lhs ) - -/** - * @brief The "equal to" operator for 64-bit timestamps. - * - * This method is the is equal to than operator for timestamps. - * - * @param[in] _lhs points to the left hand side timestamp - * @param[in] _rhs points to the right hand side timestamp - * - * @retval This method returns true if @a _lhs is equal to @a _rhs and - * false otherwise. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Equal_to( _lhs, _rhs ) \ - _Timestamp64_implementation_Equal_to( _lhs, _rhs ) -#else - bool _Timestamp64_Equal_to( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs - ); -#endif - -static inline void _Timestamp64_implementation_Add_to( - Timestamp64_Control *_time, - const Timestamp64_Control *_add -) -{ - *_time += *_add; -} - -/** - * @brief Add two 64-bit timestamps. - * - * This routine adds two timestamps. The second argument is added - * to the first. - * - * @param[in] _time points to the base time to be added to - * @param[in] _add points to the timestamp to add to the first argument - * - * @retval This method returns the number of seconds @a time increased by. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Add_to( _time, _add ) \ - _Timestamp64_implementation_Add_to( _time, _add ) -#else - void _Timestamp64_Add_to( - Timestamp64_Control *_time, - const Timestamp64_Control *_add - ); -#endif - -static inline void _Timestamp64_implementation_Subtract( - const Timestamp64_Control *_start, - const Timestamp64_Control *_end, - Timestamp64_Control *_result -) -{ - *_result = *_end - *_start; -} - -/** - * @brief Subtract two 64-bit timestamps. - * - * This routine subtracts two timestamps. @a result is set to - * @a end - @a start. - * - * @param[in] _start points to the starting time - * @param[in] _end points to the ending time - * @param[out] _result points to the difference between - * starting and ending time. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Subtract( _start, _end, _result ) \ - _Timestamp64_implementation_Subtract( _start, _end, _result ) -#else - void _Timestamp64_Subtract( - const Timestamp64_Control *_start, - const Timestamp64_Control *_end, - Timestamp64_Control *_result - ); -#endif - -/** - * @brief Divide 64-bit timestamp by another 64-bit timestamp. - * - * This routine divides a timestamp by another timestamp. The - * intended use is for calculating percentages to three decimal points. - * - * @param[in] _lhs points to the left hand number - * @param[in] _rhs points to the right hand number - * @param[out] _ival_percentage points to the integer portion of the average - * @param[out] _fval_percentage points to the thousandths of percentage - */ -void _Timestamp64_Divide( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs, - uint32_t *_ival_percentage, - uint32_t *_fval_percentage -); - -static inline uint32_t _Timestamp64_implementation_Get_seconds( - const Timestamp64_Control *_time -) -{ - return (uint32_t) (*_time / 1000000000L); -} - -/** - * @brief Get seconds portion of a 64-bit timestamp. - * - * This method returns the seconds portion of the specified timestamp - * - * @param[in] _time points to the timestamp - * - * @retval The seconds portion of @a _time. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Get_seconds( _time ) \ - _Timestamp64_implementation_Get_seconds( _time ) -#else - uint32_t _Timestamp64_Get_seconds( - const Timestamp64_Control *_time - ); -#endif - -static inline uint32_t _Timestamp64_implementation_Get_nanoseconds( - const Timestamp64_Control *_time -) -{ - return (uint32_t) (*_time % 1000000000L); -} - -/** - * @brief Get nanoseconds portion of a 64-bit timestamp. - * - * This method returns the nanoseconds portion of the specified timestamp - * - * @param[in] _time points to the timestamp - * - * @retval The nanoseconds portion of @a _time. - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_Get_nanoseconds( _time ) \ - _Timestamp64_implementation_Get_nanoseconds( _time ) -#else - uint32_t _Timestamp64_Get_nanoseconds( - const Timestamp64_Control *_time - ); -#endif - -static inline uint64_t _Timestamp64_implementation_Get_As_nanoseconds( - const Timestamp64_Control *_time, - const uint32_t nanoseconds -) -{ - return *_time + (uint64_t) nanoseconds; -} - -/** - * @brief Get the 64-bit timestamp as nanoseconds. - * - * This method returns the 64-bit timestamp as it is already in nanoseconds. - * - * @param[in] _time points to the timestamp - * - * @retval The nanoseconds portion of @a _time. - */ -#define _Timestamp64_Get_As_nanoseconds( _time, _nanoseconds ) \ - _Timestamp64_implementation_Get_As_nanoseconds( _time, _nanoseconds ) - -static inline void _Timestamp64_implementation_To_timespec( - const Timestamp64_Control *_timestamp, - struct timespec *_timespec -) -{ - _timespec->tv_sec = (time_t) (*_timestamp / 1000000000L); - _timespec->tv_nsec = (long) (*_timestamp % 1000000000L); -} - -/** - * @brief Convert 64-bit timestamp to struct timespec. - * - * This method returns the seconds portion of the specified timestamp - * - * @param[in] _timestamp points to the timestamp - * @param[out] _timespec points to the timespec - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_To_timespec( _timestamp, _timespec ) \ - _Timestamp64_implementation_To_timespec( _timestamp, _timespec ) -#else - void _Timestamp64_To_timespec( - const Timestamp64_Control *_timestamp, - struct timespec *_timespec - ); -#endif - -static inline void _Timestamp64_implementation_To_timeval( - const Timestamp64_Control *_timestamp, - struct timeval *_timeval -) -{ - _timeval->tv_sec = (time_t) (*_timestamp / 1000000000U); - _timeval->tv_usec = (suseconds_t) ((*_timestamp % 1000000000U) / 1000U); -} - -/** - * @brief Convert 64-bit timestamp to struct timeval. - * - * This method returns the seconds portion of the specified timestamp - * - * @param[in] _timestamp points to the timestamp - * @param[out] _timeval points to the timeval - */ -#if CPU_TIMESTAMP_USE_INT64_INLINE == TRUE - #define _Timestamp64_To_timeval( _timestamp, _timeval ) \ - _Timestamp64_implementation_To_timeval( _timestamp, _timeval ) -#else - void _Timestamp64_To_timeval( - const Timestamp64_Control *_timestamp, - struct timeval *_timeval - ); -#endif - -#ifdef __cplusplus -} -#endif - -/**@}*/ - -#endif -/* end of include file */ diff --git a/cpukit/score/include/rtems/score/tod.h b/cpukit/score/include/rtems/score/tod.h index 1972b0fa72..c0ab5e795d 100644 --- a/cpukit/score/include/rtems/score/tod.h +++ b/cpukit/score/include/rtems/score/tod.h @@ -24,15 +24,6 @@ extern "C" { #endif -/** - * @brief Returns the nanoseconds since the last clock tick. - * - * @ingroup ScoreTOD - * - * @return The nanoseconds since the last clock tick. - */ -typedef uint32_t ( *TOD_Nanoseconds_since_last_tick_routine )( void ); - #ifdef __cplusplus } #endif diff --git a/cpukit/score/include/rtems/score/todimpl.h b/cpukit/score/include/rtems/score/todimpl.h index ad5ed39dab..56c176d920 100644 --- a/cpukit/score/include/rtems/score/todimpl.h +++ b/cpukit/score/include/rtems/score/todimpl.h @@ -19,8 +19,8 @@ #define _RTEMS_SCORE_TODIMPL_H #include -#include #include +#include #include #include @@ -130,25 +130,6 @@ extern "C" { * @brief TOD control. */ typedef struct { - /** - * @brief Current time of day value. - * - * This field is protected by the lock. - */ - Timestamp_Control now; - - /** - * @brief System uptime. - * - * This field is protected by the lock. - */ - Timestamp_Control uptime; - - /** - * @brief Lock to protect the now and uptime fields. - */ - ISR_lock_Control lock; - /** * @brief Time of day seconds trigger. * @@ -158,13 +139,6 @@ typedef struct { */ uint32_t seconds_trigger; - /** - * @brief The current nanoseconds since last tick handler. - * - * This field must not be NULL after initialization. - */ - TOD_Nanoseconds_since_last_tick_routine nanoseconds_since_last_tick; - /** * @brief Indicates if the time of day is set. * @@ -176,12 +150,6 @@ typedef struct { SCORE_EXTERN TOD_Control _TOD; -#define _TOD_Acquire( _tod, lock_context ) \ - _ISR_lock_ISR_disable_and_acquire( &( _tod )->lock, lock_context ) - -#define _TOD_Release( _tod, lock_context ) \ - _ISR_lock_Release_and_ISR_enable( &( _tod )->lock, lock_context ) - /** * @brief Initializes the time of day handler. * @@ -201,6 +169,18 @@ void _TOD_Set_with_timestamp( const Timestamp_Control *tod_as_timestamp ); +/** + * @brief Sets the time of day from timespec. + * + * The @a tod_as_timestamp timestamp represents the time since UNIX epoch. + * The watchdog seconds chain will be adjusted. + * + * In the process the input given as timespec will be transformed to FreeBSD + * bintime format to guarantee the right format for later setting it with a + * timestamp. + * + * @param[in] tod_as_timespec is the constant of the time of day as a timespec + */ static inline void _TOD_Set( const struct timespec *tod_as_timespec ) @@ -216,31 +196,27 @@ static inline void _TOD_Set( } /** - * @brief Returns a snapshot of a clock. - * - * This function invokes the nanoseconds extension. + * @brief Gets the current time in the bintime format. * - * @param[out] snapshot points to an area that will contain the current - * TOD plus the BSP nanoseconds since last tick adjustment - * @param[in] clock contains the current TOD - * - * @retval @a snapshot + * @param[out] time is the value gathered by the bintime request */ -Timestamp_Control *_TOD_Get_with_nanoseconds( - Timestamp_Control *snapshot, - const Timestamp_Control *clock -); - static inline void _TOD_Get( - struct timespec *tod_as_timespec + Timestamp_Control *time ) { - Timestamp_Control tod_as_timestamp; - Timestamp_Control *tod_as_timestamp_ptr; + _Timecounter_Bintime(time); +} - tod_as_timestamp_ptr = - _TOD_Get_with_nanoseconds( &tod_as_timestamp, &_TOD.now ); - _Timestamp_To_timespec( tod_as_timestamp_ptr, tod_as_timespec ); +/** + * @brief Gets the current time in the timespec format. + * + * @param[out] time is the value gathered by the nanotime request + */ +static inline void _TOD_Get_as_timespec( + struct timespec *time +) +{ + _Timecounter_Nanotime(time); } /** @@ -249,26 +225,47 @@ static inline void _TOD_Get( * This routine returns the system uptime with potential accuracy * to the nanosecond. * + * The initial uptime value is undefined. + * * @param[in] time is a pointer to the uptime to be returned */ static inline void _TOD_Get_uptime( Timestamp_Control *time ) { - _TOD_Get_with_nanoseconds( time, &_TOD.uptime ); + _Timecounter_Binuptime( time ); } /** * @brief Gets the system uptime with potential accuracy to the nanosecond. - * - * This routine returns the system uptime with potential accuracy * to the nanosecond. * + * The initial uptime value is zero. + * + * @param[in] time is a pointer to the uptime to be returned + */ +static inline void _TOD_Get_zero_based_uptime( + Timestamp_Control *time +) +{ + _Timecounter_Binuptime( time ); + --time->sec; +} + +/** + * @brief Gets the system uptime with potential accuracy to the nanosecond. + * + * The initial uptime value is zero. + * * @param[in] time is a pointer to the uptime to be returned */ -void _TOD_Get_uptime_as_timespec( +static inline void _TOD_Get_zero_based_uptime_as_timespec( struct timespec *time -); +) +{ + _Timecounter_Nanouptime( time ); + --time->tv_sec; +} /** * @brief Number of seconds Since RTEMS epoch. @@ -276,7 +273,10 @@ void _TOD_Get_uptime_as_timespec( * The following contains the number of seconds from 00:00:00 * January 1, TOD_BASE_YEAR until the current time of day. */ -uint32_t _TOD_Seconds_since_epoch( void ); +static inline uint32_t _TOD_Seconds_since_epoch( void ) +{ + return (uint32_t) _Timecounter_Time_second; +} /** * @brief Increments time of day at each clock tick. @@ -314,12 +314,7 @@ RTEMS_INLINE_ROUTINE void _TOD_Get_timeval( struct timeval *time ) { - Timestamp_Control snapshot_as_timestamp; - Timestamp_Control *snapshot_as_timestamp_ptr; - - snapshot_as_timestamp_ptr = - _TOD_Get_with_nanoseconds( &snapshot_as_timestamp, &_TOD.now ); - _Timestamp_To_timeval( snapshot_as_timestamp_ptr, time ); + _Timecounter_Microtime( time ); } /** @@ -334,18 +329,6 @@ void _TOD_Adjust( const Timestamp_Control timestamp ); -/** - * @brief Install the BSP's nanoseconds since clock tick handler - * - * @param[in] routine is the BSP's nanoseconds since clock tick method - */ -RTEMS_INLINE_ROUTINE void _TOD_Set_nanoseconds_since_last_tick_handler( - TOD_Nanoseconds_since_last_tick_routine routine -) -{ - _TOD.nanoseconds_since_last_tick = routine; -} - /** * @brief Check if the TOD is Set * diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index 6804bf24d4..8405232a87 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -137,6 +137,13 @@ RTEMS_INLINE_ROUTINE void _Watchdog_Flash( */ void _Watchdog_Handler_initialization( void ); +/** + * @brief Triggers a watchdog tick. + * + * This routine executes TOD, watchdog and scheduler ticks. + */ +void _Watchdog_Tick( void ); + /** * @brief Removes @a the_watchdog from the watchdog chain. * diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 13ea020c9e..062fe1b438 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -344,10 +344,6 @@ $(PROJECT_INCLUDE)/rtems/score/timestamp.h: include/rtems/score/timestamp.h $(PR $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timestamp.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timestamp.h -$(PROJECT_INCLUDE)/rtems/score/timestamp64.h: include/rtems/score/timestamp64.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timestamp64.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timestamp64.h - $(PROJECT_INCLUDE)/rtems/score/timecounter.h: include/rtems/score/timecounter.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timecounter.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timecounter.h diff --git a/cpukit/score/src/coretod.c b/cpukit/score/src/coretod.c index 2deeebaeb3..975ffefc7d 100644 --- a/cpukit/score/src/coretod.c +++ b/cpukit/score/src/coretod.c @@ -20,24 +20,16 @@ #include -static uint32_t _TOD_Nanoseconds_since_tick_default_handler( void ) -{ - return 0; -} - void _TOD_Handler_initialization(void) { - TOD_Control *tod = &_TOD; - - _ISR_lock_Initialize( &tod->lock, "TOD" ); - - _Timestamp_Set( &tod->now, TOD_SECONDS_1970_THROUGH_1988, 0 ); + struct timespec ts; - _Timestamp_Set_to_zero( &tod->uptime ); + _Timecounter_Initialize(); - tod->nanoseconds_since_last_tick = - _TOD_Nanoseconds_since_tick_default_handler; + ts.tv_sec = TOD_SECONDS_1970_THROUGH_1988; + ts.tv_nsec = 0; + _Timecounter_Set_clock( &ts ); /* TOD has not been set */ - tod->is_set = false; + _TOD.is_set = false; } diff --git a/cpukit/score/src/coretodadjust.c b/cpukit/score/src/coretodadjust.c index 09cf01ad7c..6097e207dc 100644 --- a/cpukit/score/src/coretodadjust.c +++ b/cpukit/score/src/coretodadjust.c @@ -25,8 +25,7 @@ void _TOD_Adjust( const Timestamp_Control delta ) { - Timestamp_Control tod; - Timestamp_Control *tod_ptr; + Timestamp_Control tod; /* * Currently, RTEMS does the adjustment in one movement. @@ -41,11 +40,11 @@ void _TOD_Adjust( */ _Thread_Disable_dispatch(); - tod_ptr = _TOD_Get_with_nanoseconds( &tod, &_TOD.now ); + _TOD_Get( &tod ); - _Timestamp_Add_to( tod_ptr, &delta ); + _Timestamp_Add_to( &tod, &delta ); - _TOD_Set_with_timestamp( tod_ptr ); + _TOD_Set_with_timestamp( &tod ); _Thread_Enable_dispatch(); } diff --git a/cpukit/score/src/coretodget.c b/cpukit/score/src/coretodget.c deleted file mode 100644 index 70eb238a09..0000000000 --- a/cpukit/score/src/coretodget.c +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @file - * - * @brief Returns a Current TOD with Nanosecond Granularity - * @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 -#include - -Timestamp_Control *_TOD_Get_with_nanoseconds( - Timestamp_Control *snapshot, - const Timestamp_Control *clock -) -{ - TOD_Control *tod = &_TOD; - ISR_lock_Context lock_context; - Timestamp_Control offset; - Timestamp_Control now; - uint32_t nanoseconds; - - _TOD_Acquire( tod, &lock_context ); - nanoseconds = ( *tod->nanoseconds_since_last_tick )(); - now = *clock; - _TOD_Release( tod, &lock_context ); - - _Timestamp_Set( &offset, 0, nanoseconds ); - _Timestamp_Add_to( &now, &offset ); - - *snapshot = now; - - return snapshot; -} diff --git a/cpukit/score/src/coretodgetuptimetimespec.c b/cpukit/score/src/coretodgetuptimetimespec.c deleted file mode 100644 index 5980b2f4bd..0000000000 --- a/cpukit/score/src/coretodgetuptimetimespec.c +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file - * - * @brief Get Uptime as struct timespec - * @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 - -void _TOD_Get_uptime_as_timespec( - struct timespec *uptime -) -{ - Timestamp_Control uptime_ts; - - /* assume time checked for NULL by caller */ - _TOD_Get_uptime( &uptime_ts ); - _Timestamp_To_timespec( &uptime_ts, uptime ); -} diff --git a/cpukit/score/src/coretodsecondssinceepoch.c b/cpukit/score/src/coretodsecondssinceepoch.c deleted file mode 100644 index b7bd2705c9..0000000000 --- a/cpukit/score/src/coretodsecondssinceepoch.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * - * - * 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 - -uint32_t _TOD_Seconds_since_epoch( void ) -{ - TOD_Control *tod = &_TOD; - ISR_lock_Context lock_context; - Timestamp_Control now; - - _TOD_Acquire( tod, &lock_context ); - now = tod->now; - _TOD_Release( tod, &lock_context ); - - return _Timestamp_Get_seconds( &now ); -} diff --git a/cpukit/score/src/coretodset.c b/cpukit/score/src/coretodset.c index 3d117589a1..3230179414 100644 --- a/cpukit/score/src/coretodset.c +++ b/cpukit/score/src/coretodset.c @@ -26,20 +26,21 @@ void _TOD_Set_with_timestamp( const Timestamp_Control *tod_as_timestamp ) { - TOD_Control *tod = &_TOD; - uint32_t nanoseconds = _Timestamp_Get_nanoseconds( tod_as_timestamp ); - Watchdog_Interval seconds_next = _Timestamp_Get_seconds( tod_as_timestamp ); + struct timespec ts; + uint32_t nanoseconds; + Watchdog_Interval seconds_next; Watchdog_Interval seconds_now; - ISR_lock_Context lock_context; Watchdog_Header *header; + _Timestamp_To_timespec( tod_as_timestamp, &ts ); + nanoseconds = ts.tv_nsec; + seconds_next = ts.tv_sec; + _Thread_Disable_dispatch(); seconds_now = _TOD_Seconds_since_epoch(); - _TOD_Acquire( tod, &lock_context ); - tod->now = *tod_as_timestamp; - _TOD_Release( tod, &lock_context ); + _Timecounter_Set_clock( &ts ); header = &_Watchdog_Seconds_header; @@ -48,8 +49,8 @@ void _TOD_Set_with_timestamp( else _Watchdog_Adjust_forward( header, seconds_next - seconds_now ); - tod->seconds_trigger = nanoseconds; - tod->is_set = true; + _TOD.seconds_trigger = nanoseconds; + _TOD.is_set = true; _Thread_Enable_dispatch(); } diff --git a/cpukit/score/src/coretodtickle.c b/cpukit/score/src/coretodtickle.c index 9116fc1a3b..3d7c71e1c1 100644 --- a/cpukit/score/src/coretodtickle.c +++ b/cpukit/score/src/coretodtickle.c @@ -24,30 +24,10 @@ void _TOD_Tickle_ticks( void ) { - TOD_Control *tod = &_TOD; - ISR_lock_Context lock_context; - Timestamp_Control tick; - uint32_t nanoseconds_per_tick; - - nanoseconds_per_tick = rtems_configuration_get_nanoseconds_per_tick(); - - /* Convert the tick quantum to a timestamp */ - _Timestamp_Set( &tick, 0, nanoseconds_per_tick ); - /* Update the counter of ticks since boot */ _Watchdog_Ticks_since_boot += 1; - _TOD_Acquire( tod, &lock_context ); - - /* Update the uptime */ - _Timestamp_Add_to( &tod->uptime, &tick ); - - /* Update the current TOD */ - _Timestamp_Add_to( &tod->now, &tick ); - - _TOD_Release( tod, &lock_context ); - - _TOD.seconds_trigger += nanoseconds_per_tick; + _TOD.seconds_trigger += rtems_configuration_get_nanoseconds_per_tick(); if ( _TOD.seconds_trigger >= 1000000000UL ) { _TOD.seconds_trigger -= 1000000000UL; _Watchdog_Tickle_seconds(); diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index bca73ecb19..54799273b7 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -33,6 +33,7 @@ #define time_second _Timecounter_Time_second #define time_uptime _Timecounter_Time_uptime #include +#include #endif /* __rtems__ */ #include __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); @@ -1886,6 +1887,9 @@ _Timecounter_Tick(void) { #endif /* __rtems__ */ tc_windup(); +#ifdef __rtems__ + _Watchdog_Tick(); +#endif /* __rtems__ */ } #ifdef __rtems__ void @@ -1924,6 +1928,8 @@ _Timecounter_Tick_simple(uint32_t delta, uint32_t offset) time_uptime = th->th_offset.sec; _ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, &lock_context); + + _Watchdog_Tick(); } #endif /* __rtems__ */ diff --git a/cpukit/score/src/timespecgetasnanoseconds.c b/cpukit/score/src/timespecgetasnanoseconds.c index 4ef1af4f62..2f8d17f4a4 100644 --- a/cpukit/score/src/timespecgetasnanoseconds.c +++ b/cpukit/score/src/timespecgetasnanoseconds.c @@ -20,10 +20,9 @@ #include #include -uint64_t _Timespec_Get_As_nanoseconds( - const struct timespec *time, - const uint32_t nanoseconds +uint64_t _Timespec_Get_as_nanoseconds( + const struct timespec *time ) { - return ( ((uint64_t) time->tv_sec) * 1000000000ULL ) + time->tv_nsec + nanoseconds; + return ( ((uint64_t) time->tv_sec) * 1000000000ULL ) + time->tv_nsec; } diff --git a/cpukit/score/src/ts64addto.c b/cpukit/score/src/ts64addto.c deleted file mode 100644 index a0f4b3cf30..0000000000 --- a/cpukit/score/src/ts64addto.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file score/src/ts64addto.c - * - * @brief Add to a Timestamp - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -void _Timestamp64_Add_to( - Timestamp64_Control *_time, - const Timestamp64_Control *_add -) -{ - _Timestamp64_implementation_Add_to( _time, _add ); -} -#endif diff --git a/cpukit/score/src/ts64divide.c b/cpukit/score/src/ts64divide.c deleted file mode 100644 index d9a5099892..0000000000 --- a/cpukit/score/src/ts64divide.c +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file - * - * @brief Divide Timestamp - * @ingroup SuperCore - */ - -/* - * 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 - -/* This method is never inlined. */ -#if CPU_TIMESTAMP_USE_INT64 == TRUE || CPU_TIMESTAMP_USE_INT64_INLINE == TRUE -void _Timestamp64_Divide( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs, - uint32_t *_ival_percentage, - uint32_t *_fval_percentage -) -{ - Timestamp64_Control answer; - - if ( *_rhs == 0 ) { - *_ival_percentage = 0; - *_fval_percentage = 0; - return; - } - - /* - * This looks odd but gives the results the proper precision. - * - * TODO: Rounding on the last digit of the fval. - */ - - answer = (*_lhs * 100000) / *_rhs; - - *_ival_percentage = answer / 1000; - *_fval_percentage = answer % 1000; -} -#endif diff --git a/cpukit/score/src/ts64equalto.c b/cpukit/score/src/ts64equalto.c deleted file mode 100644 index fd07474762..0000000000 --- a/cpukit/score/src/ts64equalto.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file - * - * @brief Timestamp equal to Operator - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -bool _Timestamp64_Equal_to( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs -) -{ - return _Timestamp64_implementation_Equal_to( _lhs, _rhs ); -} -#endif diff --git a/cpukit/score/src/ts64getnanoseconds.c b/cpukit/score/src/ts64getnanoseconds.c deleted file mode 100644 index a5da43b1f1..0000000000 --- a/cpukit/score/src/ts64getnanoseconds.c +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file score/src/ts64toticks.c - * - * @brief Get Nanoseconds Portion of Timestamp - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -uint32_t _Timestamp64_Get_nanoseconds( - const Timestamp64_Control *_time -) -{ - return _Timestamp64_implementation_Get_nanoseconds( _time ); -} -#endif diff --git a/cpukit/score/src/ts64getseconds.c b/cpukit/score/src/ts64getseconds.c deleted file mode 100644 index eca0536e0e..0000000000 --- a/cpukit/score/src/ts64getseconds.c +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file - * - * @brief Get Seconds Portion of Timestamp - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -uint32_t _Timestamp64_Get_seconds( - const Timestamp64_Control *_time -) -{ - return _Timestamp64_implementation_Get_seconds( _time ); -} -#endif diff --git a/cpukit/score/src/ts64lessthan.c b/cpukit/score/src/ts64lessthan.c deleted file mode 100644 index d1478147dc..0000000000 --- a/cpukit/score/src/ts64lessthan.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file - * - * @brief Timestamp Less Than Operator - * @ingroup SuperCore Timestamp64 -*/ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -bool _Timestamp64_Less_than( - const Timestamp64_Control *_lhs, - const Timestamp64_Control *_rhs -) -{ - return _Timestamp64_implementation_Less_than( _lhs, _rhs ); -} -#endif diff --git a/cpukit/score/src/ts64set.c b/cpukit/score/src/ts64set.c deleted file mode 100644 index 22771d6980..0000000000 --- a/cpukit/score/src/ts64set.c +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * - * @brief Set Timestamp to Specified Seconds and Nanoseconds - * - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -void _Timestamp64_Set( - Timestamp64_Control *_time, - Timestamp64_Control _seconds, - Timestamp64_Control _nanoseconds -) -{ - _Timestamp64_implementation_Set( _time, _seconds, _nanoseconds ); -} -#endif diff --git a/cpukit/score/src/ts64settozero.c b/cpukit/score/src/ts64settozero.c deleted file mode 100644 index 7b319df1cf..0000000000 --- a/cpukit/score/src/ts64settozero.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file - * - * @brief Zero a Timestamp64 Instance - * - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -void _Timestamp64_Set_to_zero( - Timestamp64_Control *_time -) -{ - _Timestamp64_implementation_Set_to_zero( _time ); -} -#endif diff --git a/cpukit/score/src/ts64subtract.c b/cpukit/score/src/ts64subtract.c deleted file mode 100644 index 1ee917bb2e..0000000000 --- a/cpukit/score/src/ts64subtract.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file - * - * @brief Subtract Two Timestamps - * @ingroup Timestamp - */ -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -void _Timestamp64_Subtract( - const Timestamp64_Control *_start, - const Timestamp64_Control *_end, - Timestamp64_Control *_result -) -{ - _Timestamp64_implementation_Subtract( _start, _end, _result ); -} -#endif diff --git a/cpukit/score/src/ts64totimespec.c b/cpukit/score/src/ts64totimespec.c deleted file mode 100644 index 7e81da74e3..0000000000 --- a/cpukit/score/src/ts64totimespec.c +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file - * - * @brief Convert Timestamp to Struct Timespec - * - * @ingroup SuperCore - */ - -/* - * COPYRIGHT (c) 1989-2008. - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -void _Timestamp64_To_timespec( - const Timestamp64_Control *_timestamp, - struct timespec *_timespec -) -{ - _Timestamp64_implementation_To_timespec( _timestamp, _timespec ); -} -#endif diff --git a/cpukit/score/src/ts64totimeval.c b/cpukit/score/src/ts64totimeval.c deleted file mode 100644 index 1ac765b1ff..0000000000 --- a/cpukit/score/src/ts64totimeval.c +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file - * - * @brief Convert 64-bit Timestamp to struct timeval - * - * @ingroup SuperCore - */ - -/* - * Copyright (c) 2012 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * 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 - -#if CPU_TIMESTAMP_USE_INT64 == TRUE -void _Timestamp64_To_timeval( - const Timestamp64_Control *_timestamp, - struct timeval *_timeval -) -{ - _Timestamp64_implementation_To_timeval( _timestamp, _timeval ); -} -#endif diff --git a/cpukit/score/src/watchdogtick.c b/cpukit/score/src/watchdogtick.c new file mode 100644 index 0000000000..b9bc3f7a9c --- /dev/null +++ b/cpukit/score/src/watchdogtick.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#include +#include +#include +#include + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +void _Watchdog_Tick( void ) +{ + _TOD_Tickle_ticks(); + + _Watchdog_Tickle_ticks(); + + _Scheduler_Tick(); + + if ( _Thread_Dispatch_is_enabled() ) + _Thread_Dispatch(); +} diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 8844436876..c3fc443da0 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -39,6 +39,7 @@ _SUBDIRS += sp29 endif _SUBDIRS += spintrcritical23 _SUBDIRS += sptimecounter01 +_SUBDIRS += sptimecounter02 _SUBDIRS += spatomic01 _SUBDIRS += spintrcritical22 _SUBDIRS += spsem03 diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index d463532124..b8287a4ea7 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -42,6 +42,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes") AC_CONFIG_FILES([Makefile spintrcritical23/Makefile sptimecounter01/Makefile +sptimecounter02/Makefile spatomic01/Makefile spglobalcon01/Makefile spintrcritical22/Makefile diff --git a/testsuites/sptests/spclock_err01/init.c b/testsuites/sptests/spclock_err01/init.c index ab5c00ab1e..087c8d4a05 100644 --- a/testsuites/sptests/spclock_err01/init.c +++ b/testsuites/sptests/spclock_err01/init.c @@ -115,14 +115,6 @@ rtems_task Init( puts( "TA1 - rtems_clock_get_tod_timeval - RTEMS_NOT_DEFINED" ); } - puts( "TA1 - rtems_clock_set_nanoseconds_extension - RTEMS_INVALID_ADDRESS" ); - status = rtems_clock_set_nanoseconds_extension( NULL ); - fatal_directive_status( - status, - RTEMS_INVALID_ADDRESS, - "rtems_clock_set_nanoseconds_extension NULL param" - ); - /* NULL parameter */ status = rtems_clock_set( NULL ); fatal_directive_status( diff --git a/testsuites/sptests/spsize/size.c b/testsuites/sptests/spsize/size.c index 58bcc89312..657fa425de 100644 --- a/testsuites/sptests/spsize/size.c +++ b/testsuites/sptests/spsize/size.c @@ -390,9 +390,6 @@ uninitialized = /*timerimpl.h*/ (sizeof _Timer_Information) + -/*tod.h*/ (sizeof _TOD.now) + - (sizeof _TOD.uptime) + - /*tqdata.h*/ 0 + /*types.h*/ 0 + diff --git a/testsuites/sptests/sptimecounter02/Makefile.am b/testsuites/sptests/sptimecounter02/Makefile.am new file mode 100644 index 0000000000..badb647a14 --- /dev/null +++ b/testsuites/sptests/sptimecounter02/Makefile.am @@ -0,0 +1,20 @@ +rtems_tests_PROGRAMS = sptimecounter02 +sptimecounter02_SOURCES = init.c +sptimecounter02_SOURCES += ../../support/src/spin.c + +dist_rtems_tests_DATA = sptimecounter02.scn sptimecounter02.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 = $(sptimecounter02_OBJECTS) +LINK_LIBS = $(sptimecounter02_LDLIBS) + +sptimecounter02$(EXEEXT): $(sptimecounter02_OBJECTS) $(sptimecounter02_DEPENDENCIES) + @rm -f sptimecounter02$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/sptimecounter02/init.c b/testsuites/sptests/sptimecounter02/init.c new file mode 100644 index 0000000000..c7d72a8eb7 --- /dev/null +++ b/testsuites/sptests/sptimecounter02/init.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 + +#define _KERNEL + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "tmacros.h" + +const char rtems_test_name[] = "SPTIMECOUNTER 2"; + +#define CPU_COUNT 32 + +#define DURATION_IN_SECONDS 1 + +typedef struct { + rtems_test_parallel_context base; + struct timecounter tc_null; + uint32_t binuptime_per_job[CPU_COUNT]; + sbintime_t duration_per_job[CPU_COUNT]; + uint32_t rtemsuptime_per_job[CPU_COUNT]; +} timecounter_context; + +static timecounter_context test_instance; + +static rtems_interval test_duration(void) +{ + return DURATION_IN_SECONDS * rtems_clock_get_ticks_per_second(); +} + +static uint32_t test_get_timecount_null(struct timecounter *tc) +{ + return 0; +} + +static void install_tc_null(timecounter_context *ctx) +{ + struct timecounter *tc_cpu = &ctx->tc_null; + + tc_cpu->tc_get_timecount = test_get_timecount_null; + tc_cpu->tc_counter_mask = 0xffffffff; + tc_cpu->tc_frequency = rtems_counter_nanoseconds_to_ticks(1000000000); + tc_cpu->tc_quality = 2000; + rtems_timecounter_install(tc_cpu); +} + +static rtems_interval test_bintime_init( + rtems_test_parallel_context *base, + void *arg, + size_t active_workers +) +{ + rtems_test_spin_until_next_tick(); + + return test_duration(); +} + +static void test_bintime_body( + rtems_test_parallel_context *base, + void *arg, + size_t active_workers, + size_t worker_index +) +{ + timecounter_context *ctx = (timecounter_context *) base; + uint32_t counter = 1; + struct bintime start; + struct bintime end; + + rtems_bsd_binuptime(&start); + + do { + ++counter; + rtems_bsd_binuptime(&end); + } while (!rtems_test_parallel_stop_job(&ctx->base)); + + ctx->binuptime_per_job[worker_index] = counter; + ctx->duration_per_job[worker_index] = bttosbt(end) - bttosbt(start); +} + +static void test_bintime_fini( + rtems_test_parallel_context *base, + void *arg, + size_t active_workers +) +{ + timecounter_context *ctx = (timecounter_context *) base; + size_t i; + + printf(" \n", active_workers); + + for (i = 0; i < active_workers; ++i) { + sbintime_t error; + + printf( + " %" PRIu32 "\n" + " %" PRId64 "\n", + i + 1, + ctx->binuptime_per_job[i], + i + 1, + ctx->duration_per_job[i] + ); + + error = DURATION_IN_SECONDS * SBT_1S - ctx->duration_per_job[i]; + rtems_test_assert(error * error < SBT_1MS * SBT_1MS); + } + + printf(" \n"); +} + +static rtems_interval test_bintime_null_init( + rtems_test_parallel_context *base, + void *arg, + size_t active_workers +) +{ + timecounter_context *ctx = &test_instance; + + install_tc_null(ctx); + + return test_duration(); +} + +static void test_bintime_null_body( + rtems_test_parallel_context *base, + void *arg, + size_t active_workers, + size_t worker_index +) +{ + timecounter_context *ctx = (timecounter_context *) base; + struct bintime bt; + uint32_t counter = 0; + + while (!rtems_test_parallel_stop_job(&ctx->base)) { + ++counter; + rtems_bsd_binuptime(&bt); + } + + ctx->binuptime_per_job[worker_index] = counter; +} + +static void test_bintime_null_fini( + rtems_test_parallel_context *base, + void *arg, + size_t active_workers +) +{ + timecounter_context *ctx = (timecounter_context *) base; + size_t i; + + printf(" \n", active_workers); + + for (i = 0; i < active_workers; ++i) { + printf( + " %" PRIu32 "\n", + i + 1, + ctx->binuptime_per_job[i] + ); + } + + printf(" \n"); +} + +static const rtems_test_parallel_job timecounter_jobs[] = { + { + .init = test_bintime_init, + .body = test_bintime_body, + .fini = test_bintime_fini, + .cascade = true + },{ + .init = test_bintime_null_init, + .body = test_bintime_null_body, + .fini = test_bintime_null_fini, + .cascade = true + } +}; + +static void Init(rtems_task_argument arg) +{ + timecounter_context *ctx = &test_instance; + struct bintime bt; + struct timespec ts; + struct timeval tv; + + TEST_BEGIN(); + + printf("\n"); + + rtems_test_parallel( + &ctx->base, + NULL, + &timecounter_jobs[0], + RTEMS_ARRAY_SIZE(timecounter_jobs) + ); + + /* Check for all functions available in the bsd.h user space */ + + rtems_bsd_bintime(&bt); + rtems_bsd_microtime(&tv); + rtems_bsd_nanotime(&ts); + rtems_bsd_binuptime(&bt); + rtems_bsd_microuptime(&tv); + rtems_bsd_nanouptime(&ts); + rtems_bsd_getbintime(&bt); + rtems_bsd_getmicrotime(&tv); + rtems_bsd_getnanotime(&ts); + rtems_bsd_getbinuptime(&bt); + rtems_bsd_getmicrouptime(&tv); + rtems_bsd_getnanouptime(&ts); + + printf("\n"); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS (2 + CPU_COUNT - 1) +#define CONFIGURE_MAXIMUM_TIMERS 2 +#define CONFIGURE_MAXIMUM_PERIODS 1 + +#define CONFIGURE_SMP_APPLICATION + +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/sptests/sptimecounter02/sptimecounter02.doc b/testsuites/sptests/sptimecounter02/sptimecounter02.doc new file mode 100644 index 0000000000..9988ad067c --- /dev/null +++ b/testsuites/sptests/sptimecounter02/sptimecounter02.doc @@ -0,0 +1,12 @@ +This file describes the directives and concepts tested by this test set. + +test set name: sptimecounter02 + +directives: + + rtems_timecounter_install, rtems_bsd_binuptime. + +concepts: + + measurement of performance tests: how often per timeframe can FreeBSD time + routines be called in comparison to original rtems timing routines. diff --git a/testsuites/sptests/sptimecounter02/sptimecounter02.scn b/testsuites/sptests/sptimecounter02/sptimecounter02.scn new file mode 100644 index 0000000000..004c50e416 --- /dev/null +++ b/testsuites/sptests/sptimecounter02/sptimecounter02.scn @@ -0,0 +1,46 @@ +*** BEGIN OF TEST SPTIMECOUNTER_2 *** + + + 591457 + 4294787862 + + 587737 + 4294603178 + 587754 + 4294596307 + + 583602 + 4293605982 + 583643 + 4293602260 + 583659 + 4293604551 + + 583086 + 4291246232 + 583124 + 4291243178 + 583139 + 4291242796 + 565417 + 4291304930 + + 615571 + + + 615857 + 615856 + + + 615316 + 615328 + 615337 + + + 615495 + 615502 + 615509 + 597117 + + +*** END OF TEST SPTIMECOUNTER_2 *** -- cgit v1.2.3 From 75acd9e69f906cbd880a17ee4ca705ad7caa92c0 Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Wed, 1 Apr 2015 15:33:25 +0200 Subject: bsps: Convert clock drivers to use a timecounter Update #2271. --- c/src/lib/libbsp/arm/beagle/clock.c | 35 ++---- c/src/lib/libbsp/arm/edb7312/clock/clockdrv.c | 2 + c/src/lib/libbsp/arm/gba/clock/clockdrv.c | 2 + .../libbsp/arm/lpc176x/include/lpc-clock-config.h | 1 + .../libbsp/arm/lpc24xx/include/lpc-clock-config.h | 2 + .../libbsp/arm/lpc32xx/include/lpc-clock-config.h | 2 + c/src/lib/libbsp/arm/nds/clock/clock.c | 2 + c/src/lib/libbsp/arm/raspberrypi/clock/clockdrv.c | 12 +- .../libbsp/arm/shared/arm-a9mpcore-clock-config.c | 48 +++----- .../arm/shared/armv7m/clock/armv7m-clock-config.c | 65 ++++++----- .../libbsp/arm/shared/lpc/clock/lpc-clock-config.c | 37 +++--- c/src/lib/libbsp/arm/tms570/clock/clock.c | 40 +++---- c/src/lib/libbsp/i386/pc386/clock/ckinit.c | 125 ++++----------------- c/src/lib/libbsp/lm32/shared/clock/ckinit.c | 2 + .../libbsp/lm32/shared/milkymist_clock/ckinit.c | 2 + c/src/lib/libbsp/m68k/av5282/clock/clock.c | 2 + c/src/lib/libbsp/m68k/gen68360/clock/clock.c | 2 + c/src/lib/libbsp/m68k/genmcf548x/clock/clock.c | 2 + c/src/lib/libbsp/m68k/mcf52235/clock/clock.c | 50 +++++---- c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c | 44 ++++++-- c/src/lib/libbsp/m68k/mcf5235/clock/clock.c | 2 + c/src/lib/libbsp/m68k/mcf5329/clock/clock.c | 49 ++++---- c/src/lib/libbsp/m68k/sim68000/clock/clockdrv.c | 2 + c/src/lib/libbsp/m68k/uC5282/clock/clock.c | 48 ++++++-- c/src/lib/libbsp/mips/csb350/clock/clockdrv.c | 2 + .../lib/libbsp/mips/genmongoosev/clock/clockdrv.c | 2 + c/src/lib/libbsp/mips/jmr3904/clock/clockdrv.c | 2 + c/src/lib/libbsp/mips/rbtx4925/clock/clockdrv.c | 1 + c/src/lib/libbsp/mips/rbtx4938/clock/clockdrv.c | 2 + c/src/lib/libbsp/mips/shared/clock/clockdrv.c | 10 +- c/src/lib/libbsp/nios2/nios2_iss/clock/clock.c | 2 + .../lib/libbsp/or1k/generic_or1k/clock/clockdrv.c | 50 +++++---- .../libbsp/powerpc/mpc55xxevb/clock/clock-config.c | 96 ++++++++++------ .../lib/libbsp/powerpc/qoriq/clock/clock-config.c | 61 +++++----- c/src/lib/libbsp/powerpc/qoriq/configure.ac | 4 + c/src/lib/libbsp/powerpc/shared/clock/clock.c | 56 +++------ c/src/lib/libbsp/shared/clock_driver_simidle.c | 2 + c/src/lib/libbsp/shared/clockdrv_shell.h | 52 ++++++--- c/src/lib/libbsp/sparc/erc32/clock/ckinit.c | 52 ++++++--- c/src/lib/libbsp/sparc/leon2/clock/ckinit.c | 52 ++++++--- c/src/lib/libbsp/sparc/leon3/clock/ckinit.c | 97 +++++++++++----- c/src/lib/libbsp/sparc64/shared/clock/ckinit.c | 2 + c/src/lib/libcpu/arm/at91rm9200/clock/clock.c | 23 +--- c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c | 53 ++++++--- c/src/lib/libcpu/arm/mc9328mxl/clock/clockdrv.c | 3 + c/src/lib/libcpu/arm/pxa255/clock/clock.c | 2 + c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c | 14 +-- c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c | 107 +++++------------- 48 files changed, 685 insertions(+), 640 deletions(-) diff --git a/c/src/lib/libbsp/arm/beagle/clock.c b/c/src/lib/libbsp/arm/beagle/clock.c index 66aba1b84b..912d904197 100644 --- a/c/src/lib/libbsp/arm/beagle/clock.c +++ b/c/src/lib/libbsp/arm/beagle/clock.c @@ -15,11 +15,12 @@ */ #include +#include #include #include -#ifdef ARM_MULTILIB_ARCH_V4 +static struct timecounter beagle_clock_tc; static omap_timer_registers_t regs_v1 = { .TIDR = OMAP3_TIMER_TIDR, @@ -115,8 +116,6 @@ static struct omap_timer *timer = &am335x_timer; #endif -static int done = 0; - #if IS_AM335X #define FRCLOCK_HZ (16*1500000) #endif @@ -181,20 +180,14 @@ omap3_frclock_init(void) /* Start timer, without prescaler */ mmio_set(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST); - done = 1; } -static inline uint32_t -read_frc(void) +static uint32_t +beagle_clock_get_timecount(struct timecounter *tc) { - if (done == 0) { - return 0; - } return mmio_read(fr_timer->base + fr_timer->regs->TCRR); } -static uint32_t last_tick_nanoseconds; - static void beagle_clock_initialize(void) { @@ -262,12 +255,16 @@ beagle_clock_initialize(void) while(mmio_read(AM335X_WDT_BASE+AM335X_WDT_WWPS) != 0) ; #endif + /* Install timecounter */ \ + beagle_clock_tc.tc_get_timecount = beagle_clock_get_timecount; + beagle_clock_tc.tc_counter_mask = 0xffffffff; + beagle_clock_tc.tc_frequency = FRCLOCK_HZ; + beagle_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&beagle_clock_tc); } static void beagle_clock_at_tick(void) { - last_tick_nanoseconds = read_frc(); - mmio_write(timer->base + timer->regs->TISR, OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | OMAP3_TISR_TCAR_IT_FLAG); @@ -315,14 +312,6 @@ static void beagle_clock_cleanup(void) mmio_clear(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_ST); } -static inline uint32_t beagle_clock_nanoseconds_since_last_tick(void) -{ - /* this arithmetic also works if read_frc() wraps around, as long - * as the subtraction wraps around too - */ - return (read_frc() - (uint64_t) last_tick_nanoseconds) * 1000000000 / FRCLOCK_HZ; -} - #define Clock_driver_support_at_tick() beagle_clock_at_tick() #define Clock_driver_support_initialize_hardware() beagle_clock_initialize() #define Clock_driver_support_install_isr(isr, old_isr) \ @@ -332,10 +321,6 @@ static inline uint32_t beagle_clock_nanoseconds_since_last_tick(void) } while (0) #define Clock_driver_support_shutdown_hardware() beagle_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - beagle_clock_nanoseconds_since_last_tick /* Include shared source clock driver code */ #include "../../shared/clockdrv_shell.h" - -#endif /* ARM_MULTILIB_ARCH_V4 */ diff --git a/c/src/lib/libbsp/arm/edb7312/clock/clockdrv.c b/c/src/lib/libbsp/arm/edb7312/clock/clockdrv.c index 499a27904c..121b2c9d32 100644 --- a/c/src/lib/libbsp/arm/edb7312/clock/clockdrv.c +++ b/c/src/lib/libbsp/arm/edb7312/clock/clockdrv.c @@ -68,4 +68,6 @@ void Clock_isr(void * arg); assert(status == RTEMS_SUCCESSFUL); \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/gba/clock/clockdrv.c b/c/src/lib/libbsp/arm/gba/clock/clockdrv.c index 72d0b81e32..ff171110b9 100644 --- a/c/src/lib/libbsp/arm/gba/clock/clockdrv.c +++ b/c/src/lib/libbsp/arm/gba/clock/clockdrv.c @@ -92,4 +92,6 @@ void Clock_driver_support_initialize_hardware(void) GBA_REG_TM3CNT = (0x00c0|GBA_TMCNT_PS); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/lpc176x/include/lpc-clock-config.h b/c/src/lib/libbsp/arm/lpc176x/include/lpc-clock-config.h index c72575f719..3eef02152e 100644 --- a/c/src/lib/libbsp/arm/lpc176x/include/lpc-clock-config.h +++ b/c/src/lib/libbsp/arm/lpc176x/include/lpc-clock-config.h @@ -33,6 +33,7 @@ extern "C" { #define LPC_CLOCK_INTERRUPT LPC176X_IRQ_TIMER_0 #define LPC_CLOCK_TIMER_BASE TMR0_BASE_ADDR +#define LPC_CLOCK_TIMECOUNTER_BASE TMR1_BASE_ADDR #define LPC_CLOCK_REFERENCE LPC176X_PCLK #define LPC_CLOCK_MODULE_ENABLE() \ lpc176x_module_enable( LPC176X_MODULE_TIMER_0, LPC176X_MODULE_PCLK_DEFAULT ) diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/lpc-clock-config.h b/c/src/lib/libbsp/arm/lpc24xx/include/lpc-clock-config.h index 1edab4eb02..5e6b469e0f 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/include/lpc-clock-config.h +++ b/c/src/lib/libbsp/arm/lpc24xx/include/lpc-clock-config.h @@ -35,6 +35,8 @@ extern "C" { #define LPC_CLOCK_TIMER_BASE TMR0_BASE_ADDR +#define LPC_CLOCK_TIMECOUNTER_BASE TMR1_BASE_ADDR + #define LPC_CLOCK_REFERENCE LPC24XX_PCLK #define LPC_CLOCK_MODULE_ENABLE() \ diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/lpc-clock-config.h b/c/src/lib/libbsp/arm/lpc32xx/include/lpc-clock-config.h index accd0d256a..2b676b433f 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/lpc-clock-config.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/lpc-clock-config.h @@ -44,6 +44,8 @@ extern "C" { #define LPC_CLOCK_TIMER_BASE LPC32XX_BASE_TIMER_0 +#define LPC_CLOCK_TIMECOUNTER_BASE LPC32XX_BASE_TIMER_1 + #define LPC_CLOCK_REFERENCE LPC32XX_PERIPH_CLK #define LPC_CLOCK_MODULE_ENABLE() diff --git a/c/src/lib/libbsp/arm/nds/clock/clock.c b/c/src/lib/libbsp/arm/nds/clock/clock.c index a24f8cc788..1e239d44d9 100644 --- a/c/src/lib/libbsp/arm/nds/clock/clock.c +++ b/c/src/lib/libbsp/arm/nds/clock/clock.c @@ -81,4 +81,6 @@ void Clock_driver_support_initialize_hardware (void) TIMER_DATA (0) = TIMER_FREQ_64 ((uint16_t) freq); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/raspberrypi/clock/clockdrv.c b/c/src/lib/libbsp/arm/raspberrypi/clock/clockdrv.c index 533873cf19..f765485570 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/clock/clockdrv.c +++ b/c/src/lib/libbsp/arm/raspberrypi/clock/clockdrv.c @@ -72,14 +72,6 @@ static void raspberrypi_clock_cleanup(void) } } -/* - * Return the nanoseconds since last tick - */ -static uint32_t raspberrypi_clock_nanoseconds_since_last_tick(void) -{ - return 0; -} - #define Clock_driver_support_at_tick() raspberrypi_clock_at_tick() #define Clock_driver_support_initialize_hardware() raspberrypi_clock_initialize() @@ -92,8 +84,6 @@ static uint32_t raspberrypi_clock_nanoseconds_since_last_tick(void) #define Clock_driver_support_shutdown_hardware() raspberrypi_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - raspberrypi_clock_nanoseconds_since_last_tick - +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/shared/arm-a9mpcore-clock-config.c b/c/src/lib/libbsp/arm/shared/arm-a9mpcore-clock-config.c index f2ce07e3b6..8e2e153b46 100644 --- a/c/src/lib/libbsp/arm/shared/arm-a9mpcore-clock-config.c +++ b/c/src/lib/libbsp/arm/shared/arm-a9mpcore-clock-config.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2013-2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -17,14 +17,11 @@ #include #include #include +#include #define A9MPCORE_GT ((volatile a9mpcore_gt *) BSP_ARM_A9MPCORE_GT_BASE) -static uint64_t a9mpcore_clock_last_tick_k; - -static uint32_t a9mpcore_clock_last_tick_cmpvallower; - -static uint32_t a9mpcore_clock_autoinc; +static struct timecounter a9mpcore_tc; /* This is defined in clockdrv_shell.h */ void Clock_isr(rtems_irq_hdl_param arg); @@ -39,13 +36,6 @@ static void a9mpcore_clock_at_tick(void) { volatile a9mpcore_gt *gt = A9MPCORE_GT; - /* - * FIXME: Now the _TOD_Get_with_nanoseconds() yields wrong values until - * _TOD_Tickle_ticks() managed to update the uptime. See also PR2180. - */ - a9mpcore_clock_last_tick_cmpvallower = - gt->cmpvallower - a9mpcore_clock_autoinc; - gt->irqst = A9MPCORE_GT_IRQST_EFLG; } @@ -80,6 +70,13 @@ static uint64_t a9mpcore_clock_get_counter(volatile a9mpcore_gt *gt) return ((uint64_t) cu2 << 32) | cl; } +static uint32_t a9mpcore_clock_get_timecount(struct timecounter *tc) +{ + volatile a9mpcore_gt *gt = A9MPCORE_GT; + + return gt->cntrlower; +} + static void a9mpcore_clock_initialize(void) { volatile a9mpcore_gt *gt = A9MPCORE_GT; @@ -98,14 +95,16 @@ static void a9mpcore_clock_initialize(void) gt->cmpvalupper = (uint32_t) (cmpval >> 32); gt->autoinc = interval; - a9mpcore_clock_last_tick_k = (UINT64_C(1000000000) << 32) / periphclk; - a9mpcore_clock_last_tick_cmpvallower = (uint32_t) cmpval - interval; - a9mpcore_clock_autoinc = interval; - gt->ctrl = A9MPCORE_GT_CTRL_AUTOINC_EN | A9MPCORE_GT_CTRL_IRQ_EN | A9MPCORE_GT_CTRL_COMP_EN | A9MPCORE_GT_CTRL_TMR_EN; + + a9mpcore_tc.tc_get_timecount = a9mpcore_clock_get_timecount; + a9mpcore_tc.tc_counter_mask = 0xffffffff; + a9mpcore_tc.tc_frequency = periphclk; + a9mpcore_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&a9mpcore_tc); } CPU_Counter_ticks _CPU_Counter_read(void) @@ -147,16 +146,6 @@ static void a9mpcore_clock_cleanup(void) } } -static uint32_t a9mpcore_clock_nanoseconds_since_last_tick(void) -{ - volatile a9mpcore_gt *gt = A9MPCORE_GT; - uint64_t k = a9mpcore_clock_last_tick_k; - uint32_t n = a9mpcore_clock_last_tick_cmpvallower; - uint32_t c = gt->cntrlower; - - return (uint32_t) (((c - n) * k) >> 32); -} - #define Clock_driver_support_at_tick() \ a9mpcore_clock_at_tick() @@ -165,15 +154,12 @@ static uint32_t a9mpcore_clock_nanoseconds_since_last_tick(void) #define Clock_driver_support_install_isr(isr, old_isr) \ do { \ - a9mpcore_clock_handler_install(); \ + a9mpcore_clock_handler_install(); \ old_isr = NULL; \ } while (0) #define Clock_driver_support_shutdown_hardware() \ a9mpcore_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - a9mpcore_clock_nanoseconds_since_last_tick - /* Include shared source clock driver code */ #include "../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/shared/armv7m/clock/armv7m-clock-config.c b/c/src/lib/libbsp/arm/shared/armv7m/clock/armv7m-clock-config.c index 8e4ae338f8..e78684c8d2 100644 --- a/c/src/lib/libbsp/arm/shared/armv7m/clock/armv7m-clock-config.c +++ b/c/src/lib/libbsp/arm/shared/armv7m/clock/armv7m-clock-config.c @@ -13,6 +13,7 @@ */ #include +#include #include #include @@ -22,15 +23,35 @@ /* This is defined in clockdrv_shell.h */ static void Clock_isr(void *arg); -#define _ARMV7M_Systick_get_factor(freq) \ - ((1000000000ULL << 32) / (freq)) +static rtems_timecounter_simple _ARMV7M_TC; -#ifdef BSP_ARMV7M_SYSTICK_FREQUENCY - #define _ARMV7M_Systick_factor \ - _ARMV7M_Systick_get_factor(BSP_ARMV7M_SYSTICK_FREQUENCY) -#else - static uint64_t _ARMV7M_Systick_factor; -#endif +static uint32_t _ARMV7M_TC_get(rtems_timecounter_simple *tc) +{ + volatile ARMV7M_Systick *systick = _ARMV7M_Systick; + + return systick->cvr; +} + +static bool _ARMV7M_TC_is_pending(rtems_timecounter_simple *tc) +{ + volatile ARMV7M_SCB *scb = _ARMV7M_SCB; + + return ((scb->icsr & ARMV7M_SCB_ICSR_PENDSTSET) != 0); +} + +static uint32_t _ARMV7M_TC_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + _ARMV7M_TC_get, + _ARMV7M_TC_is_pending + ); +} + +static void _ARMV7M_TC_tick(void) +{ + rtems_timecounter_simple_downcounter_tick(&_ARMV7M_TC, _ARMV7M_TC_get); +} static void _ARMV7M_Systick_at_tick(void) { @@ -67,15 +88,18 @@ static void _ARMV7M_Systick_initialize(void) uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); uint64_t interval = (freq * us_per_tick) / 1000000ULL; - #ifndef BSP_ARMV7M_SYSTICK_FREQUENCY - _ARMV7M_Systick_factor = _ARMV7M_Systick_get_factor(freq); - #endif - systick->rvr = (uint32_t) interval; systick->cvr = 0; systick->csr = ARMV7M_SYSTICK_CSR_ENABLE | ARMV7M_SYSTICK_CSR_TICKINT | ARMV7M_SYSTICK_CSR_CLKSOURCE; + + rtems_timecounter_simple_install( + &_ARMV7M_TC, + freq, + interval, + _ARMV7M_TC_get_timecount + ); } static void _ARMV7M_Systick_cleanup(void) @@ -85,19 +109,7 @@ static void _ARMV7M_Systick_cleanup(void) systick->csr = 0; } -static uint32_t _ARMV7M_Systick_nanoseconds_since_last_tick(void) -{ - volatile ARMV7M_Systick *systick = _ARMV7M_Systick; - volatile ARMV7M_SCB *scb = _ARMV7M_SCB; - uint32_t rvr = systick->rvr; - uint32_t c = rvr - systick->cvr; - - if ((scb->icsr & ARMV7M_SCB_ICSR_PENDSTSET) != 0) { - c = rvr - systick->cvr + rvr; - } - - return (uint32_t) ((c * _ARMV7M_Systick_factor) >> 32); -} +#define Clock_driver_timecounter_tick() _ARMV7M_TC_tick() #define Clock_driver_support_at_tick() \ _ARMV7M_Systick_at_tick() @@ -114,9 +126,6 @@ static uint32_t _ARMV7M_Systick_nanoseconds_since_last_tick(void) #define Clock_driver_support_shutdown_hardware() \ _ARMV7M_Systick_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - _ARMV7M_Systick_nanoseconds_since_last_tick - /* Include shared source clock driver code */ #include "../../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c b/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c index 05c94a6b2c..a55ba0e33c 100644 --- a/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c +++ b/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c @@ -7,10 +7,10 @@ */ /* - * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. + * Copyright (c) 2009-2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH - * Obere Lagerstr. 30 + * Dornierstr. 4 * 82178 Puchheim * Germany * @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -33,6 +34,16 @@ void Clock_isr(rtems_irq_hdl_param arg); static volatile lpc_timer *const lpc_clock = (volatile lpc_timer *) LPC_CLOCK_TIMER_BASE; +static volatile lpc_timer *const lpc_timecounter = + (volatile lpc_timer *) LPC_CLOCK_TIMECOUNTER_BASE; + +static struct timecounter lpc_clock_tc; + +static uint32_t lpc_clock_tc_get_timecount(struct timecounter *tc) +{ + return lpc_timecounter->tc; +} + static void lpc_clock_at_tick(void) { lpc_clock->ir = LPC_TIMER_IR_MR0; @@ -56,6 +67,7 @@ static void lpc_clock_handler_install(void) static void lpc_clock_initialize(void) { + uint32_t mask; uint64_t interval = ((uint64_t) LPC_CLOCK_REFERENCE * (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000; @@ -85,6 +97,13 @@ static void lpc_clock_initialize(void) /* Enable timer */ lpc_clock->tcr = LPC_TIMER_TCR_EN; + + /* Install timecounter */ + lpc_clock_tc.tc_get_timecount = lpc_clock_tc_get_timecount; + lpc_clock_tc.tc_counter_mask = 0xffffffff; + lpc_clock_tc.tc_frequency = LPC_CLOCK_REFERENCE; + lpc_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&lpc_clock_tc); } static void lpc_clock_cleanup(void) @@ -105,18 +124,6 @@ static void lpc_clock_cleanup(void) } } -static uint32_t lpc_clock_nanoseconds_since_last_tick(void) -{ - uint64_t k = (1000000000ULL << 32) / LPC_CLOCK_REFERENCE; - uint64_t c = lpc_clock->tc; - - if ((lpc_clock->ir & LPC_TIMER_IR_MR0) != 0) { - c = lpc_clock->tc + lpc_clock->mr0; - } - - return (uint32_t) ((c * k) >> 32); -} - #define Clock_driver_support_at_tick() lpc_clock_at_tick() #define Clock_driver_support_initialize_hardware() lpc_clock_initialize() #define Clock_driver_support_install_isr(isr, old_isr) \ @@ -126,8 +133,6 @@ static uint32_t lpc_clock_nanoseconds_since_last_tick(void) } while (0) #define Clock_driver_support_shutdown_hardware() lpc_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - lpc_clock_nanoseconds_since_last_tick /* Include shared source clock driver code */ #include "../../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/arm/tms570/clock/clock.c b/c/src/lib/libbsp/arm/tms570/clock/clock.c index 4dba949c86..d438a3da34 100644 --- a/c/src/lib/libbsp/arm/tms570/clock/clock.c +++ b/c/src/lib/libbsp/arm/tms570/clock/clock.c @@ -30,13 +30,14 @@ #include #include #include +#include -/** - * holds HW counter value since last interrupt event - * sets in tms570_clock_driver_support_at_tick - * used in tms570_clock_driver_nanoseconds_since_last_tick - */ -static uint32_t tms570_rti_last_tick_fcr0; +static struct timecounter tms570_rti_tc; + +static uint32_t tms570_rti_get_timecount(struct timecounter tc) +{ + return TMS570_RTI.RTIFRC0; +} /** * @brief Initialize the HW peripheral for clock driver @@ -72,6 +73,12 @@ static void tms570_clock_driver_support_initialize_hardware( void ) TMS570_RTI.RTISETINTENA = 0x1; /* enable timer */ TMS570_RTI.RTIGCTRL = 1; + /* set timecounter */ + tms570_rti_tc.tc_get_timecount = tms570_rti_get_timecount; + tms570_rti_tc.tc_counter_mask = 0xffffffff; + tms570_rti_tc.tc_frequency = BSP_PLL_OUT_CLOCK; + tms570_rti_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&tms570_rti_tc); } /** @@ -82,7 +89,6 @@ static void tms570_clock_driver_support_initialize_hardware( void ) static void tms570_clock_driver_support_at_tick( void ) { TMS570_RTI.RTIINTFLAG = 0x00000001; - tms570_rti_last_tick_fcr0 = TMS570_RTI.RTICOMP0 - TMS570_RTI.RTIUDCP0; } /** @@ -124,24 +130,6 @@ static void tms570_clock_driver_support_shutdown_hardware( void ) TMS570_RTI.RTICLEARINTENA = 0x20000; } -/** - * @brief returns the nanoseconds since last tick - * - * Return the nanoseconds since last tick - * - * @retval x nanoseconds - * - */ -static uint32_t tms570_clock_driver_nanoseconds_since_last_tick( void ) -{ - uint32_t actual_fcr0 = TMS570_RTI.RTIFRC0; - uint32_t usec_since_tick; - - usec_since_tick = actual_fcr0 - tms570_rti_last_tick_fcr0; - - return usec_since_tick * 1000; -} - #define Clock_driver_support_initialize_hardware \ tms570_clock_driver_support_initialize_hardware #define Clock_driver_support_at_tick \ @@ -150,8 +138,6 @@ static uint32_t tms570_clock_driver_nanoseconds_since_last_tick( void ) tms570_clock_driver_support_initialize_hardware #define Clock_driver_support_shutdown_hardware \ tms570_clock_driver_support_shutdown_hardware -#define Clock_driver_nanoseconds_since_last_tick \ - tms570_clock_driver_nanoseconds_since_last_tick #define Clock_driver_support_install_isr(Clock_isr, Old_ticker ) \ tms570_clock_driver_support_install_isr( Clock_isr ) diff --git a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c index 2782252680..44a35bc6c1 100644 --- a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c +++ b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c @@ -28,6 +28,7 @@ #include #include #include +#include #define CLOCK_VECTOR 0 @@ -39,29 +40,24 @@ uint32_t pc386_clock_click_count; void Clock_isr(void *param); static void Clock_driver_support_at_tick_empty(void); static void clockOff(void); -static void Clock_driver_support_at_tick_tsc(void); -static uint32_t bsp_clock_nanoseconds_since_last_tick_tsc(void); -static uint32_t bsp_clock_nanoseconds_since_last_tick_i8254(void); static void Clock_isr_handler(void *param); /* - * Roughly the number of cycles per tick and per nanosecond. Note that these + * Roughly the number of cycles per second. Note that these * will be wildly inaccurate if the chip speed changes due to power saving * or thermal modes. * * NOTE: These are only used when the TSC method is used. */ -uint64_t pc586_tsc_per_tick; -uint64_t pc586_nanoseconds_per_tick; +static uint64_t pc586_tsc_frequency; -uint64_t pc586_tsc_at_tick; +static struct timecounter pc386_tc; /* this driver may need to count ISRs per tick */ #define CLOCK_DRIVER_ISRS_PER_TICK 1 #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE pc386_isrs_per_tick -/* The driver uses the count in Clock_driver_support_at_tick */ -extern volatile uint32_t Clock_driver_isrs; +extern volatile uint32_t Clock_driver_ticks; #define READ_8254( _lsb, _msb ) \ do { outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); \ @@ -74,60 +70,21 @@ extern volatile uint32_t Clock_driver_isrs; * Hooks which get swapped based upon which nanoseconds since last * tick method is preferred. */ -void (*Clock_driver_support_at_tick)(void) = NULL; -uint32_t (*Clock_driver_nanoseconds_since_last_tick)(void) = NULL; - -/* - * What do we do at each clock tick? - */ -static void Clock_driver_support_at_tick_tsc(void) -{ - pc586_tsc_at_tick = rdtsc(); -} - -static void Clock_driver_support_at_tick_empty(void) -{ -} +#define Clock_driver_support_at_tick() #define Clock_driver_support_install_isr( _new, _old ) \ do { \ _old = NULL; \ } while(0) -/* - * Get nanoseconds using Pentium-compatible TSC register - */ -static uint32_t bsp_clock_nanoseconds_since_last_tick_tsc(void) +static uint32_t pc386_get_timecount_tsc(struct timecounter *tc) { - uint64_t diff_nsec; - - diff_nsec = rdtsc() - pc586_tsc_at_tick; - - /* - * At this point, with a hypothetical 10 GHz CPU clock and 100 Hz tick - * clock, diff_nsec <= 27 bits. - */ - diff_nsec *= pc586_nanoseconds_per_tick; /* <= 54 bits */ - diff_nsec /= pc586_tsc_per_tick; - - if (diff_nsec > pc586_nanoseconds_per_tick) - /* - * Hmmm... Some drift or rounding. Pin the value to 1 nanosecond before - * the next tick. - */ - /* diff_nsec = pc586_nanoseconds_per_tick - 1; */ - diff_nsec = 12345; - - return (uint32_t)diff_nsec; + return (uint32_t)rdtsc(); } -/* - * Get nanoseconds using 8254 timer chip - */ -static uint32_t bsp_clock_nanoseconds_since_last_tick_i8254(void) +static uint32_t pc386_get_timecount_i8254(struct timecounter *tc) { - uint32_t usecs, clicks, isrs; - uint32_t usecs1, usecs2; + uint32_t irqs; uint8_t lsb, msb; rtems_interrupt_level level; @@ -136,34 +93,10 @@ static uint32_t bsp_clock_nanoseconds_since_last_tick_i8254(void) */ rtems_interrupt_disable(level); READ_8254(lsb, msb); - isrs = Clock_driver_isrs; + irqs = Clock_driver_ticks; rtems_interrupt_enable(level); - /* - * Now do the math - */ - /* convert values read into counter clicks */ - clicks = ((msb << 8) | lsb); - - /* whole ISRs we have done since the last tick */ - usecs1 = (pc386_isrs_per_tick - isrs - 1) * pc386_microseconds_per_isr; - - /* the partial ISR we in the middle of now */ - usecs2 = pc386_microseconds_per_isr - TICK_TO_US(clicks); - - /* total microseconds */ - usecs = usecs1 + usecs2; - #if 0 - printk( "usecs1=%d usecs2=%d ", usecs1, usecs2 ); - printk( "maxclicks=%d clicks=%d ISRs=%d ISRsper=%d usersPer=%d usecs=%d\n", - pc386_clock_click_count, clicks, - Clock_driver_isrs, pc386_isrs_per_tick, - pc386_microseconds_per_isr, usecs ); - #endif - - /* return it in nanoseconds */ - return usecs * 1000; - + return (irqs + 1) * pc386_microseconds_per_isr - ((msb << 8) | lsb); } /* @@ -175,9 +108,6 @@ static void calibrate_tsc(void) uint8_t then_lsb, then_msb, now_lsb, now_msb; uint32_t i; - pc586_nanoseconds_per_tick = - rtems_configuration_get_microseconds_per_tick() * 1000; - /* * We just reset the timer, so we know we're at the beginning of a tick. */ @@ -204,16 +134,11 @@ static void calibrate_tsc(void) } while (1); } - pc586_tsc_per_tick = rdtsc() - begin_time; - - /* Initialize "previous tick" counters */ - pc586_tsc_at_tick = rdtsc(); + pc586_tsc_frequency = rdtsc() - begin_time; #if 0 - printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_per_tick / 1000000)); + printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / 1000000)); #endif - - pc586_tsc_per_tick /= rtems_clock_get_ticks_per_second(); } static void clockOn(void) @@ -299,24 +224,18 @@ void Clock_driver_support_initialize_hardware(void) if ( use_8254 ) { /* printk( "Use 8254\n" ); */ - Clock_driver_support_at_tick = Clock_driver_support_at_tick_empty; - Clock_driver_nanoseconds_since_last_tick = - bsp_clock_nanoseconds_since_last_tick_i8254; + pc386_tc.tc_get_timecount = pc386_get_timecount_i8254; + pc386_tc.tc_counter_mask = 0xffffffff; + pc386_tc.tc_frequency = TIMER_TICK; } else { /* printk( "Use TSC\n" ); */ - Clock_driver_support_at_tick = Clock_driver_support_at_tick_tsc; - Clock_driver_nanoseconds_since_last_tick = - bsp_clock_nanoseconds_since_last_tick_tsc; + pc386_tc.tc_get_timecount = pc386_get_timecount_tsc; + pc386_tc.tc_counter_mask = 0xffffffff; + pc386_tc.tc_frequency = pc586_tsc_frequency; } - /* Shell installs nanosecond handler before calling - * Clock_driver_support_initialize_hardware() :-( - * so we do it again now that we're ready. - */ - rtems_clock_set_nanoseconds_extension( - Clock_driver_nanoseconds_since_last_tick - ); - + pc386_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&pc386_tc); Clock_isr_enabled = true; } diff --git a/c/src/lib/libbsp/lm32/shared/clock/ckinit.c b/c/src/lib/libbsp/lm32/shared/clock/ckinit.c index ae065de0d8..b1f5c8d0b9 100644 --- a/c/src/lib/libbsp/lm32/shared/clock/ckinit.c +++ b/c/src/lib/libbsp/lm32/shared/clock/ckinit.c @@ -75,5 +75,7 @@ static void Clock_driver_support_shutdown_hardware(void) clockwrite(LM32_CLOCK_CR, LM32_CLOCK_CR_STOP); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c b/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c index 65651e6470..3230d83325 100644 --- a/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c +++ b/c/src/lib/libbsp/lm32/shared/milkymist_clock/ckinit.c @@ -46,4 +46,6 @@ static void Clock_driver_support_shutdown_hardware(void) MM_WRITE(MM_TIMER0_CONTROL, 0); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/av5282/clock/clock.c b/c/src/lib/libbsp/m68k/av5282/clock/clock.c index 3dded8adf1..182693fe03 100644 --- a/c/src/lib/libbsp/m68k/av5282/clock/clock.c +++ b/c/src/lib/libbsp/m68k/av5282/clock/clock.c @@ -58,4 +58,6 @@ MCF5282_PIT_PCSR_EN; \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/gen68360/clock/clock.c b/c/src/lib/libbsp/m68k/gen68360/clock/clock.c index 78deaf9cce..3b9d4ca293 100644 --- a/c/src/lib/libbsp/m68k/gen68360/clock/clock.c +++ b/c/src/lib/libbsp/m68k/gen68360/clock/clock.c @@ -98,4 +98,6 @@ extern int m360_clock_rate; m360.pitr |= divisor; \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/genmcf548x/clock/clock.c b/c/src/lib/libbsp/m68k/genmcf548x/clock/clock.c index d3f6eb467c..d0f28c6b72 100644 --- a/c/src/lib/libbsp/m68k/genmcf548x/clock/clock.c +++ b/c/src/lib/libbsp/m68k/genmcf548x/clock/clock.c @@ -98,5 +98,7 @@ MCF548X_SLT_SCR0 |= (MCF548X_SLT_SCR_TEN | MCF548X_SLT_SCR_RUN | MCF548X_SLT_SCR_IEN); \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c b/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c index c22393d5ae..7a508a3b1c 100644 --- a/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c +++ b/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c @@ -3,6 +3,7 @@ */ #include +#include #include /* @@ -10,34 +11,37 @@ */ #define CLOCK_VECTOR (64+56) -static uint32_t s_pcntrAtTick = 0; -static uint32_t s_nanoScale = 0; +static rtems_timecounter_simple mcf52235_tc; -/* - * Provide nanosecond extension - * Interrupts are disabled when this is called - */ -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) +static uint32_t mcf52235_tc_get(rtems_timecounter_simple *tc) { - uint32_t i; + return MCF_PIT1_PCNTR; +} - if (MCF_PIT1_PCSR & MCF_PIT_PCSR_PIF) { - i = s_pcntrAtTick + (MCF_PIT1_PMR - MCF_PIT1_PCNTR); - } - else { - i = s_pcntrAtTick - MCF_PIT1_PCNTR; - } - return i * s_nanoScale; +static bool mcf52235_tc_is_pending(rtems_timecounter_simple *tc) +{ + return (MCF_PIT1_PCSR & MCF_PIT_PCSR_PIF) != 0; } -#define Clock_driver_nanoseconds_since_last_tick bsp_clock_nanoseconds_since_last_tick +static uint32_t mcf52235_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + mcf52235_tc_get, + mcf52235_tc_is_pending + ); +} + +static void mcf52235_tc_tick(void) +{ + rtems_timecounter_simple_downcounter_tick(&mcf52235_tc, mcf52235_tc_get); +} /* * Periodic interval timer interrupt handler */ #define Clock_driver_support_at_tick() \ do { \ - s_pcntrAtTick = MCF_PIT1_PCNTR; \ MCF_PIT1_PCSR |= MCF_PIT_PCSR_PIF; \ } while (0) \ @@ -64,6 +68,7 @@ static void Clock_driver_support_shutdown_hardware(void) */ static void Clock_driver_support_initialize_hardware(void) { + uint32_t mask; int level; uint32_t pmr; uint32_t preScaleCode = 0; @@ -76,7 +81,6 @@ static void Clock_driver_support_initialize_hardware(void) break; preScaleCode++; } - s_nanoScale = 1000000000 / (clk >> preScaleCode); MCF_INTC0_ICR56 = MCF_INTC_ICR_IL(PIT3_IRQ_LEVEL) | MCF_INTC_ICR_IP(PIT3_IRQ_PRIORITY); @@ -90,7 +94,15 @@ static void Clock_driver_support_initialize_hardware(void) MCF_PIT1_PMR = pmr; MCF_PIT1_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) | MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD | MCF_PIT_PCSR_EN; - s_pcntrAtTick = MCF_PIT1_PCNTR; + + rtems_timecounter_simple_install( + &mcf52235_tc, + clk >> preScaleCode, + pmr, + mcf52235_tc_get_timecount + ); } +#define Clock_driver_timecounter_tick() mcf52235_tc_tick() + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c b/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c index d058126798..33fd76c0ae 100644 --- a/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c +++ b/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c @@ -3,6 +3,7 @@ */ #include +#include #include /* @@ -10,26 +11,37 @@ */ #define CLOCK_VECTOR (64+56) -static uint32_t s_pcntrAtTick = 0; -static uint32_t s_nanoScale = 0; +static rtems_timecounter_simple mcf5225x_tc; -/* - * Provide nanosecond extension - * Interrupts are disabled when this is called - */ -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) +static uint32_t mcf5225x_tc_get(rtems_timecounter_simple *tc) +{ + return MCF_PIT1_PCNTR; +} + +static bool mcf5225x_tc_is_pending(rtems_timecounter_simple *tc) +{ + return (MCF_PIT1_PCSR & MCF_PIT_PCSR_PIF) != 0; +} + +static uint32_t mcf5225x_tc_get_timecount(struct timecounter *tc) { - return MCF_PIT1_PCSR & MCF_PIT_PCSR_PIF ? (s_pcntrAtTick + (MCF_PIT1_PMR - MCF_PIT1_PCNTR)) * s_nanoScale : (s_pcntrAtTick - MCF_PIT1_PCNTR) * s_nanoScale; + return rtems_timecounter_simple_downcounter_get( + tc, + mcf5225x_tc_get, + mcf5225x_tc_is_pending + ); } -#define Clock_driver_nanoseconds_since_last_tick bsp_clock_nanoseconds_since_last_tick +static void mcf5225x_tc_tick(void) +{ + rtems_timecounter_simple_downcounter_tick(&mcf5225x_tc, mcf5225x_tc_get); +} /* * Periodic interval timer interrupt handler */ #define Clock_driver_support_at_tick() \ do { \ - s_pcntrAtTick = MCF_PIT1_PCNTR; \ MCF_PIT1_PCSR |= MCF_PIT_PCSR_PIF; \ } while (0) \ @@ -56,6 +68,7 @@ static void Clock_driver_support_shutdown_hardware(void) */ static void Clock_driver_support_initialize_hardware(void) { + uint32_t mask; int level; uint32_t pmr; uint32_t preScaleCode = 0; @@ -68,7 +81,6 @@ static void Clock_driver_support_initialize_hardware(void) break; preScaleCode++; } - s_nanoScale = 1000000000 / (clk >> preScaleCode); MCF_INTC0_ICR56 = MCF_INTC_ICR_IL(PIT3_IRQ_LEVEL) | MCF_INTC_ICR_IP(PIT3_IRQ_PRIORITY); @@ -82,7 +94,15 @@ static void Clock_driver_support_initialize_hardware(void) MCF_PIT1_PMR = pmr; MCF_PIT1_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) | MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD | MCF_PIT_PCSR_EN; - s_pcntrAtTick = MCF_PIT1_PCNTR; + + rtems_timecounter_simple_install( + &mcf5225x_tc, + clk >> preScaleCode, + pmr, + mcf5225x_tc_get_timecount + ); } +#define Clock_driver_timecounter_tick() mcf5225x_tc_tick() + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/mcf5235/clock/clock.c b/c/src/lib/libbsp/m68k/mcf5235/clock/clock.c index c057796e59..95b7f37bac 100644 --- a/c/src/lib/libbsp/m68k/mcf5235/clock/clock.c +++ b/c/src/lib/libbsp/m68k/mcf5235/clock/clock.c @@ -58,4 +58,6 @@ MCF5235_PIT_PCSR_EN; \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/mcf5329/clock/clock.c b/c/src/lib/libbsp/m68k/mcf5329/clock/clock.c index ed11320bba..94c5bb0b04 100644 --- a/c/src/lib/libbsp/m68k/mcf5329/clock/clock.c +++ b/c/src/lib/libbsp/m68k/mcf5329/clock/clock.c @@ -3,6 +3,7 @@ */ #include +#include #include /* @@ -10,36 +11,40 @@ */ #define CLOCK_VECTOR (128+46) -static uint32_t s_pcntrAtTick = 0; -static uint32_t s_nanoScale = 0; +static rtems_timecounter_simple mcf5329_tc; -/* - * Provide nanosecond extension - */ -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) +static uint32_t mcf5329_tc_get(rtems_timecounter_simple *tc) { - uint32_t i; + return MCF_PIT3_PCNTR; +} - if (MCF_PIT3_PCSR & MCF_PIT_PCSR_PIF) { - i = s_pcntrAtTick + (MCF_PIT3_PMR - MCF_PIT3_PCNTR); - } else { - i = s_pcntrAtTick - MCF_PIT3_PCNTR; - } - return i * s_nanoScale; +static bool mcf5329_tc_is_pending(rtems_timecounter_simple *tc) +{ + return (MCF_PIT3_PCSR & MCF_PIT_PCSR_PIF) != 0; +} + +static uint32_t mcf5329_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + mcf5329_tc_get, + mcf5329_tc_is_pending + ); } -#define Clock_driver_nanoseconds_since_last_tick bsp_clock_nanoseconds_since_last_tick +static void mcf5329_tc_tick(void) +{ + rtems_timecounter_simple_downcounter_tick(&mcf5329_tc, mcf5329_tc_get); +} /* * Periodic interval timer interrupt handler */ #define Clock_driver_support_at_tick() \ do { \ - s_pcntrAtTick = MCF_PIT3_PCNTR; \ MCF_PIT3_PCSR |= MCF_PIT_PCSR_PIF; \ } while (0) \ - /* * Attach clock interrupt handler */ @@ -75,8 +80,6 @@ static void Clock_driver_support_initialize_hardware(void) break; preScaleCode++; } - s_nanoScale = 1000000000 / (clk >> preScaleCode); - MCF_INTC1_ICR46 = MCF_INTC_ICR_IL(PIT3_IRQ_LEVEL); rtems_interrupt_disable(level); @@ -89,7 +92,15 @@ static void Clock_driver_support_initialize_hardware(void) MCF_PIT3_PMR = pmr; MCF_PIT3_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) | MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD | MCF_PIT_PCSR_EN; - s_pcntrAtTick = MCF_PIT3_PCNTR; + + rtems_timecounter_simple_install( + &mcf5329_tc, + clk >> preScaleCode, + pmr, + mcf5329_tc_get_timecount + ); } +#define Clock_driver_timecounter_tick() mcf5329_tc_tick() + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/sim68000/clock/clockdrv.c b/c/src/lib/libbsp/m68k/sim68000/clock/clockdrv.c index 3cf981863a..0a78abc15f 100644 --- a/c/src/lib/libbsp/m68k/sim68000/clock/clockdrv.c +++ b/c/src/lib/libbsp/m68k/sim68000/clock/clockdrv.c @@ -48,4 +48,6 @@ static void Clock_driver_support_shutdown_hardware(void) t->cr = 0xA0; /* initialize with timer disabled */ } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/m68k/uC5282/clock/clock.c b/c/src/lib/libbsp/m68k/uC5282/clock/clock.c index 8636f96fe0..46e045cae3 100644 --- a/c/src/lib/libbsp/m68k/uC5282/clock/clock.c +++ b/c/src/lib/libbsp/m68k/uC5282/clock/clock.c @@ -12,6 +12,7 @@ */ #include +#include #include #include @@ -20,6 +21,32 @@ */ #define CLOCK_VECTOR (64+58) +static rtems_timecounter_simple uC5282_tc; + +static uint32_t uC5282_tc_get(rtems_timecounter_simple *tc) +{ + return MCF5282_PIT3_PCNTR; +} + +static bool uC5282_tc_is_pending(rtems_timecounter_simple *tc) +{ + return (MCF5282_PIT3_PCSR & MCF5282_PIT_PCSR_PIF) != 0; +} + +static uint32_t uC5282_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + uC5282_tc_get, + uC5282_tc_is_pending + ); +} + +static void uC5282_tc_tick(void) +{ + rtems_timecounter_simple_downcounter_tick(&uC5282_tc, uC5282_tc_get); +} + /* * CPU load counters * Place in static RAM so updates don't hit the SDRAM @@ -31,17 +58,6 @@ #define NSEC_PER_PITC __SRAMBASE.nsec_per_pitc #define FILTER_SHIFT 6 -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) -{ - int i = MCF5282_PIT3_PCNTR; - if (MCF5282_PIT3_PCSR & MCF5282_PIT_PCSR_PIF) - i = MCF5282_PIT3_PCNTR - PITC_PER_TICK; - return (PITC_PER_TICK - i) * NSEC_PER_PITC; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick - /* * Periodic interval timer interrupt handler */ @@ -83,7 +99,7 @@ static uint32_t bsp_clock_nanoseconds_since_last_tick(void) */ #define Clock_driver_support_initialize_hardware() \ do { \ - unsigned long long N; \ + unsigned long long N; \ int level; \ int preScaleCode = 0; \ N = bsp_get_CPU_clock_speed(); \ @@ -116,6 +132,12 @@ static uint32_t bsp_clock_nanoseconds_since_last_tick(void) MCF5282_PIT_PCSR_PIE | \ MCF5282_PIT_PCSR_RLD | \ MCF5282_PIT_PCSR_EN; \ + rtems_timecounter_simple_install( \ + &uC5282_tc, \ + bsp_get_CPU_clock_speed() >> (preScaleCode + 1), \ + PITC_PER_TICK, \ + uC5282_tc_get_timecount \ + ); \ } while (0) /* @@ -135,4 +157,6 @@ int bsp_cpu_load_percentage(void) 0; } +#define Clock_driver_timecounter_tick() uC5282_tc_tick() + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/mips/csb350/clock/clockdrv.c b/c/src/lib/libbsp/mips/csb350/clock/clockdrv.c index c733a1b19a..537bf7ee1e 100644 --- a/c/src/lib/libbsp/mips/csb350/clock/clockdrv.c +++ b/c/src/lib/libbsp/mips/csb350/clock/clockdrv.c @@ -88,4 +88,6 @@ void au1x00_clock_init(void) #define Clock_driver_support_shutdown_hardware() +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/mips/genmongoosev/clock/clockdrv.c b/c/src/lib/libbsp/mips/genmongoosev/clock/clockdrv.c index 05c1a92ac4..20f730ad6b 100644 --- a/c/src/lib/libbsp/mips/genmongoosev/clock/clockdrv.c +++ b/c/src/lib/libbsp/mips/genmongoosev/clock/clockdrv.c @@ -54,4 +54,6 @@ #define Clock_driver_support_shutdown_hardware() \ MONGOOSEV_WRITE_REGISTER( CLOCK_BASE, MONGOOSEV_TIMER_CONTROL_REGISTER, 0 ) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/mips/jmr3904/clock/clockdrv.c b/c/src/lib/libbsp/mips/jmr3904/clock/clockdrv.c index 4aa1f9ebb6..f3bcbe25f1 100644 --- a/c/src/lib/libbsp/mips/jmr3904/clock/clockdrv.c +++ b/c/src/lib/libbsp/mips/jmr3904/clock/clockdrv.c @@ -55,4 +55,6 @@ #define Clock_driver_support_shutdown_hardware() +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/mips/rbtx4925/clock/clockdrv.c b/c/src/lib/libbsp/mips/rbtx4925/clock/clockdrv.c index 4a45c9a955..2fb56c6eb9 100644 --- a/c/src/lib/libbsp/mips/rbtx4925/clock/clockdrv.c +++ b/c/src/lib/libbsp/mips/rbtx4925/clock/clockdrv.c @@ -123,5 +123,6 @@ TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TCR, 0x0 ); /* Disable timer */ \ } while(0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/mips/rbtx4938/clock/clockdrv.c b/c/src/lib/libbsp/mips/rbtx4938/clock/clockdrv.c index f50c6d2fdc..59b3452d88 100644 --- a/c/src/lib/libbsp/mips/rbtx4938/clock/clockdrv.c +++ b/c/src/lib/libbsp/mips/rbtx4938/clock/clockdrv.c @@ -114,4 +114,6 @@ void new_brk_esr(void) } while(0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/mips/shared/clock/clockdrv.c b/c/src/lib/libbsp/mips/shared/clock/clockdrv.c index 8ee52c63ed..8b178bbd52 100644 --- a/c/src/lib/libbsp/mips/shared/clock/clockdrv.c +++ b/c/src/lib/libbsp/mips/shared/clock/clockdrv.c @@ -43,17 +43,11 @@ static uint32_t mips_timer_rate = 0; mips_enable_in_interrupt_mask(CLOCK_VECTOR_MASK); \ } while(0) -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) -{ - return 0; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick - #define Clock_driver_support_shutdown_hardware() \ do { \ mips_disable_in_interrupt_mask(CLOCK_VECTOR_MASK); \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/nios2/nios2_iss/clock/clock.c b/c/src/lib/libbsp/nios2/nios2_iss/clock/clock.c index 939af651c5..1656e763c1 100644 --- a/c/src/lib/libbsp/nios2/nios2_iss/clock/clock.c +++ b/c/src/lib/libbsp/nios2/nios2_iss/clock/clock.c @@ -49,5 +49,7 @@ static void Clock_driver_support_initialize_hardware(void) NIOS2_IENABLE(1 << CLOCK_VECTOR); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/or1k/generic_or1k/clock/clockdrv.c b/c/src/lib/libbsp/or1k/generic_or1k/clock/clockdrv.c index 57e46c1897..e01d2e506d 100644 --- a/c/src/lib/libbsp/or1k/generic_or1k/clock/clockdrv.c +++ b/c/src/lib/libbsp/or1k/generic_or1k/clock/clockdrv.c @@ -22,11 +22,14 @@ #include #include #include +#include /* The number of clock cycles before generating a tick timer interrupt. */ #define TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT 0x09ED9 #define OR1K_CLOCK_CYCLE_TIME_NANOSECONDS 10 +static struct timecounter or1ksim_tc; + /* CPU counter */ static CPU_Counter_ticks cpu_counter_ticks; @@ -69,8 +72,23 @@ static void generic_or1k_clock_handler_install( } } +static uint32_t or1ksim_get_timecount(struct timecounter *tc) +{ + uint32_t ticks_since_last_timer_interrupt; + + ticks_since_last_timer_interrupt = _OR1K_mfspr(CPU_OR1K_SPR_TTCR); + + return cpu_counter_ticks + ticks_since_last_timer_interrupt; +} + +CPU_Counter_ticks _CPU_Counter_read(void) +{ + return or1ksim_get_timecount(NULL); +} + static void generic_or1k_clock_initialize(void) { + uint64_t frequency = (1000000000 / OR1K_CLOCK_CYCLE_TIME_NANOSECONDS); uint32_t TTMR; /* For TTMR register, @@ -90,11 +108,15 @@ static void generic_or1k_clock_initialize(void) _OR1K_mtspr(CPU_OR1K_SPR_TTMR, TTMR); _OR1K_mtspr(CPU_OR1K_SPR_TTCR, 0); - /* Initialize CPU Counter */ - cpu_counter_ticks = 0; + /* Initialize timecounter */ + or1ksim_tc.tc_get_timecount = or1ksim_get_timecount; + or1ksim_tc.tc_counter_mask = 0xffffffff; + or1ksim_tc.tc_frequency = frequency; + or1ksim_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&or1ksim_tc); } - static void generic_or1k_clock_cleanup(void) +static void generic_or1k_clock_cleanup(void) { uint32_t sr; @@ -109,24 +131,6 @@ static void generic_or1k_clock_initialize(void) _OR1K_mtspr(CPU_OR1K_SPR_TTMR, 0); } -/* - * Return the nanoseconds since last tick - */ -static uint32_t generic_or1k_clock_nanoseconds_since_last_tick(void) -{ - return - TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT * OR1K_CLOCK_CYCLE_TIME_NANOSECONDS; -} - -CPU_Counter_ticks _CPU_Counter_read(void) -{ - uint32_t ticks_since_last_timer_interrupt; - - ticks_since_last_timer_interrupt = _OR1K_mfspr(CPU_OR1K_SPR_TTCR); - - return cpu_counter_ticks + ticks_since_last_timer_interrupt; -} - CPU_Counter_ticks _CPU_Counter_difference( CPU_Counter_ticks second, CPU_Counter_ticks first @@ -134,6 +138,7 @@ CPU_Counter_ticks _CPU_Counter_difference( { return second - first; } + #define Clock_driver_support_at_tick() generic_or1k_clock_at_tick() #define Clock_driver_support_initialize_hardware() generic_or1k_clock_initialize() @@ -146,7 +151,4 @@ CPU_Counter_ticks _CPU_Counter_difference( #define Clock_driver_support_shutdown_hardware() generic_or1k_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - generic_or1k_clock_nanoseconds_since_last_tick - #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c index 5743dcff35..5724f9bf4b 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c @@ -26,14 +26,40 @@ #include +#include + void Clock_isr(void *arg); -static uint64_t mpc55xx_clock_factor; +static rtems_timecounter_simple mpc55xx_tc; #if defined(MPC55XX_CLOCK_EMIOS_CHANNEL) #include +static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc) +{ + return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CCNTR.R; +} + +static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc) +{ + return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.B.FLAG != 0; +} + +static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_upcounter_get( + tc, + mpc55xx_tc_get, + mpc55xx_tc_is_pending + ); +} + +static void mpc55xx_tc_tick(void) +{ + rtems_timecounter_simple_upcounter_tick(&mpc55xx_tc, mpc55xx_tc_get); +} + static void mpc55xx_clock_at_tick(void) { union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; @@ -60,6 +86,7 @@ static void mpc55xx_clock_handler_install(rtems_isr_entry isr) static void mpc55xx_clock_initialize(void) { + uint32_t mask; volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS; union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; @@ -68,8 +95,6 @@ static void mpc55xx_clock_initialize(void) uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); uint64_t interval = (reference_clock * us_per_tick) / 1000000; - mpc55xx_clock_factor = (1000000000ULL << 32) / reference_clock; - /* Apply prescaler */ if (prescaler > 0) { interval /= (uint64_t) prescaler; @@ -110,6 +135,13 @@ static void mpc55xx_clock_initialize(void) ccr.B.FEN = 1; ccr.B.FREN = 1; regs->CCR.R = ccr.R; + + rtems_timecounter_simple_install( + &mpc55xx_tc, + reference_clock, + interval, + mpc55xx_tc_get_timecount + ); } static void mpc55xx_clock_cleanup(void) @@ -122,21 +154,31 @@ static void mpc55xx_clock_cleanup(void) regs->CCR.R = ccr.R; } -static uint32_t mpc55xx_clock_nanoseconds_since_last_tick(void) +#elif defined(MPC55XX_CLOCK_PIT_CHANNEL) + +static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc) { - volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; - uint64_t c = regs->CCNTR.R; - union EMIOS_CSR_tag csr = { .R = regs->CSR.R }; - uint64_t k = mpc55xx_clock_factor; + return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].CVAL.R; +} - if (csr.B.FLAG != 0) { - c = regs->CCNTR.R + regs->CADR.R + 1; - } +static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc) +{ + return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].TFLG.B.TIF != 0; +} - return (uint32_t) ((c * k) >> 32); +static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + mpc55xx_tc_get, + mpc55xx_tc_is_pending + ); } -#elif defined(MPC55XX_CLOCK_PIT_CHANNEL) +static void mpc55xx_tc_tick(void) +{ + rtems_timecounter_simple_downcounter_tick(&mpc55xx_tc, mpc55xx_tc_get); +} static void mpc55xx_clock_at_tick(void) { @@ -166,6 +208,7 @@ static void mpc55xx_clock_handler_install(rtems_isr_entry isr) static void mpc55xx_clock_initialize(void) { + uint32_t mask; volatile PIT_RTI_CHANNEL_tag *channel = &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL]; uint64_t reference_clock = bsp_clock_speed; @@ -174,11 +217,16 @@ static void mpc55xx_clock_initialize(void) PIT_RTI_PITMCR_32B_tag pitmcr = { .B = { .FRZ = 1 } }; PIT_RTI_TCTRL_32B_tag tctrl = { .B = { .TIE = 1, .TEN = 1 } }; - mpc55xx_clock_factor = (1000000000ULL << 32) / reference_clock; - PIT_RTI.PITMCR.R = pitmcr.R; channel->LDVAL.R = interval; channel->TCTRL.R = tctrl.R; + + rtems_timecounter_simple_install( + &mpc55xx_tc, + reference_clock, + interval, + mpc55xx_tc_get_timecount + ); } static void mpc55xx_clock_cleanup(void) @@ -189,23 +237,9 @@ static void mpc55xx_clock_cleanup(void) channel->TCTRL.R = 0; } -static uint32_t mpc55xx_clock_nanoseconds_since_last_tick(void) -{ - volatile PIT_RTI_CHANNEL_tag *channel = - &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL]; - uint32_t c = channel->CVAL.R; - uint32_t i = channel->LDVAL.R; - uint64_t k = mpc55xx_clock_factor; - - if (channel->TFLG.B.TIF != 0) { - c = channel->CVAL.R - i; - } - - return (uint32_t) (((i - c) * k) >> 32); -} - #endif +#define Clock_driver_timecounter_tick() mpc55xx_tc_tick() #define Clock_driver_support_at_tick() \ mpc55xx_clock_at_tick() #define Clock_driver_support_initialize_hardware() \ @@ -217,8 +251,6 @@ static uint32_t mpc55xx_clock_nanoseconds_since_last_tick(void) } while (0) #define Clock_driver_support_shutdown_hardware() \ mpc55xx_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - mpc55xx_clock_nanoseconds_since_last_tick /* Include shared source clock driver code */ #include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/powerpc/qoriq/clock/clock-config.c b/c/src/lib/libbsp/powerpc/qoriq/clock/clock-config.c index 039edde46e..c6300e254f 100644 --- a/c/src/lib/libbsp/powerpc/qoriq/clock/clock-config.c +++ b/c/src/lib/libbsp/powerpc/qoriq/clock/clock-config.c @@ -7,10 +7,10 @@ */ /* - * Copyright (c) 2011-2012 embedded brains GmbH. All rights reserved. + * Copyright (c) 2011-2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH - * Obere Lagerstr. 30 + * Dornierstr. 4 * 82178 Puchheim * Germany * @@ -20,6 +20,8 @@ * http://www.rtems.org/license/LICENSE. */ +#include + #include #include @@ -29,10 +31,6 @@ /* This is defined in clockdrv_shell.h */ static rtems_isr Clock_isr(void *arg); -static uint32_t qoriq_clock_last_ccr; - -static uint32_t qoriq_clock_nanoseconds_per_timer_tick; - static volatile qoriq_pic_global_timer *const qoriq_clock = #if QORIQ_CLOCK_TIMER < 4 &qoriq.pic.gta [QORIQ_CLOCK_TIMER]; @@ -40,8 +38,17 @@ static volatile qoriq_pic_global_timer *const qoriq_clock = &qoriq.pic.gtb [QORIQ_CLOCK_TIMER - 4]; #endif +static volatile qoriq_pic_global_timer *const qoriq_timecounter = + #if QORIQ_CLOCK_TIMECOUNTER < 4 + &qoriq.pic.gta [QORIQ_CLOCK_TIMECOUNTER]; + #else + &qoriq.pic.gtb [QORIQ_CLOCK_TIMECOUNTER - 4]; + #endif + #define CLOCK_INTERRUPT (QORIQ_IRQ_GT_BASE + QORIQ_CLOCK_TIMER) +static struct timecounter qoriq_clock_tc; + static void qoriq_clock_handler_install(rtems_isr_entry *old_isr) { rtems_status_code sc = RTEMS_SUCCESSFUL; @@ -77,18 +84,28 @@ static void qoriq_clock_handler_install(rtems_isr_entry *old_isr) } } +static uint32_t qoriq_clock_get_timecount(struct timecounter *tc) +{ + uint32_t ccr = qoriq_timecounter->ccr; + + return GTCCR_COUNT_GET(-ccr); +} + static void qoriq_clock_initialize(void) { uint32_t timer_frequency = BSP_bus_frequency / 8; - uint32_t nanoseconds_per_second = 1000000000; uint32_t interval = (uint32_t) (((uint64_t) timer_frequency * (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000); - qoriq_clock_nanoseconds_per_timer_tick = - nanoseconds_per_second / timer_frequency; - qoriq_clock->bcr = GTBCR_COUNT(interval); - qoriq_clock_last_ccr = qoriq_clock->ccr; + + qoriq_timecounter->bcr = GTBCR_COUNT(0xffffffff); + + qoriq_clock_tc.tc_get_timecount = qoriq_clock_get_timecount; + qoriq_clock_tc.tc_counter_mask = GTCCR_COUNT_GET(0xffffffff); + qoriq_clock_tc.tc_frequency = timer_frequency; + qoriq_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&qoriq_clock_tc); } static void qoriq_clock_cleanup(void) @@ -107,33 +124,13 @@ static void qoriq_clock_cleanup(void) } } -static void qoriq_clock_at_tick(void) -{ - qoriq_clock_last_ccr = qoriq_clock->ccr; -} - -static uint32_t qoriq_clock_nanoseconds_since_last_tick(void) -{ - uint32_t ccr = qoriq_clock->ccr; - uint32_t bcr = qoriq_clock->bcr; - - if ((ccr & GTCCR_TOG) != (qoriq_clock_last_ccr & GTCCR_TOG)) { - bcr += bcr; - } - - return (bcr - GTCCR_COUNT_GET(ccr)) * qoriq_clock_nanoseconds_per_timer_tick; -} - -#define Clock_driver_support_at_tick() \ - qoriq_clock_at_tick() +#define Clock_driver_support_at_tick() #define Clock_driver_support_initialize_hardware() \ qoriq_clock_initialize() #define Clock_driver_support_install_isr(clock_isr, old_isr) \ qoriq_clock_handler_install(&old_isr) #define Clock_driver_support_shutdown_hardware() \ qoriq_clock_cleanup() -#define Clock_driver_nanoseconds_since_last_tick \ - qoriq_clock_nanoseconds_since_last_tick /* Include shared source clock driver code */ #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/powerpc/qoriq/configure.ac b/c/src/lib/libbsp/powerpc/qoriq/configure.ac index f1ff103d7c..409ac193c4 100644 --- a/c/src/lib/libbsp/powerpc/qoriq/configure.ac +++ b/c/src/lib/libbsp/powerpc/qoriq/configure.ac @@ -154,6 +154,10 @@ RTEMS_BSPOPTS_SET([QORIQ_CLOCK_TIMER],[qoriq_core_1],[4]) RTEMS_BSPOPTS_SET([QORIQ_CLOCK_TIMER],[*],[0]) RTEMS_BSPOPTS_HELP([QORIQ_CLOCK_TIMER],[global timer used for system clock, 0..3 maps to A0..A3, and 4..7 maps to B0..B3]) +RTEMS_BSPOPTS_SET([QORIQ_CLOCK_TIMECOUNTER],[qoriq_core_1],[5]) +RTEMS_BSPOPTS_SET([QORIQ_CLOCK_TIMECOUNTER],[*],[1]) +RTEMS_BSPOPTS_HELP([QORIQ_CLOCK_TIMECOUNTER],[global timer used for the timecounter, 0..3 maps to A0..A3, and 4..7 maps to B0..B3]) + RTEMS_BSPOPTS_SET([QORIQ_CHIP_VARIANT],[qoriq_t2080*],[QORIQ_CHIP_T2080]) RTEMS_BSPOPTS_SET([QORIQ_CHIP_VARIANT],[qoriq_t4240*],[QORIQ_CHIP_T4240]) RTEMS_BSPOPTS_SET([QORIQ_CHIP_VARIANT],[*],[QORIQ_CHIP_P1020]) diff --git a/c/src/lib/libbsp/powerpc/shared/clock/clock.c b/c/src/lib/libbsp/powerpc/shared/clock/clock.c index e9b1d4d24a..d2f2d0d1b0 100644 --- a/c/src/lib/libbsp/powerpc/shared/clock/clock.c +++ b/c/src/lib/libbsp/powerpc/shared/clock/clock.c @@ -7,7 +7,7 @@ */ /* - * Copyright (c) 2008-2013 embedded brains GmbH. All rights reserved. + * Copyright (c) 2008-2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Obere Lagerstr. 30 @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -46,7 +47,12 @@ static uint32_t ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX; static uint32_t ppc_clock_next_time_base; -static uint64_t ppc_clock_factor; +static struct timecounter ppc_tc; + +static uint32_t ppc_get_timecount(struct timecounter *tc) +{ + return ppc_time_base(); +} static void ppc_clock_no_tick(void) { @@ -161,28 +167,6 @@ static int ppc_clock_exception_handler_ppc405(BSP_Exception_frame *frame, unsign return 0; } -static uint32_t ppc_clock_nanoseconds_since_last_tick(void) -{ - uint64_t k = ppc_clock_factor; - uint32_t c = ppc_decrementer_register(); - uint32_t i = ppc_clock_decrementer_value + 1; - - return (uint32_t) (((i - c) * k) >> 32); -} - -static uint32_t ppc_clock_nanoseconds_since_last_tick_ppc405(void) -{ - uint64_t k = ppc_clock_factor; - uint32_t i = ppc_clock_decrementer_value; - uint32_t c = i - PPC_SPECIAL_PURPOSE_REGISTER(PPC405_PIT); - - if ((PPC_SPECIAL_PURPOSE_REGISTER(PPC405_TSR) & BOOKE_TSR_DIS) != 0) { - c = i - PPC_SPECIAL_PURPOSE_REGISTER(PPC405_PIT) + i; - } - - return (uint32_t) ((c * k) >> 32); -} - void Clock_exit(void) { /* Set the decrementer to the maximum value */ @@ -201,18 +185,12 @@ rtems_device_driver Clock_initialize( uint64_t frequency = bsp_time_base_frequency; uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000); + uint32_t mask; /* * Set default ticker. - * - * The function rtems_clock_tick() returns a status code. This value - * will be discarded since the RTEMS documentation claims that it is - * always successful. */ - ppc_clock_tick = (void (*)(void)) rtems_clock_tick; - - /* Factor for nano seconds extension */ - ppc_clock_factor = (1000000000ULL << 32) / frequency; + ppc_clock_tick = rtems_timecounter_tick; if (ppc_cpu_is_bookE() != PPC_BOOKE_405) { /* Decrementer value */ @@ -223,10 +201,6 @@ rtems_device_driver Clock_initialize( ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX; RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n"); } - - /* Set the nanoseconds since last tick handler */ - rtems_clock_set_nanoseconds_extension( ppc_clock_nanoseconds_since_last_tick); - if (ppc_cpu_is_bookE()) { /* Set decrementer auto-reload value */ PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value); @@ -253,9 +227,6 @@ rtems_device_driver Clock_initialize( /* PIT interval value */ ppc_clock_decrementer_value = interval; - /* Set the nanoseconds since last tick handler */ - rtems_clock_set_nanoseconds_extension(ppc_clock_nanoseconds_since_last_tick_ppc405); - /* Install exception handler */ ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405); @@ -266,5 +237,12 @@ rtems_device_driver Clock_initialize( PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval); } + /* Install timecounter */ + ppc_tc.tc_get_timecount = ppc_get_timecount; + ppc_tc.tc_counter_mask = 0xffffffff; + ppc_tc.tc_frequency = frequency; + ppc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&ppc_tc); + return RTEMS_SUCCESSFUL; } diff --git a/c/src/lib/libbsp/shared/clock_driver_simidle.c b/c/src/lib/libbsp/shared/clock_driver_simidle.c index 0f94b1e56b..ee4b116b40 100644 --- a/c/src/lib/libbsp/shared/clock_driver_simidle.c +++ b/c/src/lib/libbsp/shared/clock_driver_simidle.c @@ -28,6 +28,8 @@ volatile bool clock_driver_enabled; clock_driver_enabled = false; \ } while (0) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "clockdrv_shell.h" /* diff --git a/c/src/lib/libbsp/shared/clockdrv_shell.h b/c/src/lib/libbsp/shared/clockdrv_shell.h index 5dbea1335f..628ba58672 100644 --- a/c/src/lib/libbsp/shared/clockdrv_shell.h +++ b/c/src/lib/libbsp/shared/clockdrv_shell.h @@ -20,6 +20,10 @@ #include #include +#ifdef Clock_driver_nanoseconds_since_last_tick +#error "Update driver to use the timecounter instead of nanoseconds extension" +#endif + /** * @defgroup bsp_clock Clock Support * @@ -39,6 +43,18 @@ #define Clock_driver_support_find_timer() #endif +/* + * A specialized clock driver may use for example rtems_timecounter_tick_simple() + * instead of the default. + */ +#ifndef Clock_driver_timecounter_tick + #ifdef CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #define Clock_driver_timecounter_tick() rtems_clock_tick() + #else + #define Clock_driver_timecounter_tick() rtems_timecounter_tick() + #endif +#endif + /** * @brief ISRs until next clock tick */ @@ -78,16 +94,24 @@ rtems_isr Clock_isr( Clock_driver_ticks += 1; #if CLOCK_DRIVER_USE_FAST_IDLE - do { - rtems_clock_tick(); - } while ( - _Thread_Heir == _Thread_Executing - && _Thread_Executing->Start.entry_point - == (Thread_Entry) rtems_configuration_get_idle_task() - ); + { + struct timecounter *tc = _Timecounter; + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint32_t interval = (uint32_t) + ((tc->tc_frequency * us_per_tick) / 1000000); + + Clock_driver_timecounter_tick(); + + while ( + _Thread_Heir == _Thread_Executing + && _Thread_Executing->Start.entry_point + == (Thread_Entry) rtems_configuration_get_idle_task() + ) { + _Timecounter_Tick_simple(interval, (*tc->tc_get_timecount)(tc)); + } - Clock_driver_support_at_tick(); - return; + Clock_driver_support_at_tick(); + } #else /* * Do the hardware specific per-tick action. @@ -101,7 +125,7 @@ rtems_isr Clock_isr( * The driver is multiple ISRs per clock tick. */ if ( !Clock_driver_isrs ) { - rtems_clock_tick(); + Clock_driver_timecounter_tick(); Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK; } @@ -110,7 +134,7 @@ rtems_isr Clock_isr( /* * The driver is one ISR per clock tick. */ - rtems_clock_tick(); + Clock_driver_timecounter_tick(); #endif #endif } @@ -160,12 +184,6 @@ rtems_device_driver Clock_initialize( (void) Old_ticker; Clock_driver_support_install_isr( Clock_isr, Old_ticker ); - #if defined(Clock_driver_nanoseconds_since_last_tick) - rtems_clock_set_nanoseconds_extension( - Clock_driver_nanoseconds_since_last_tick - ); - #endif - /* * Now initialize the hardware that is the source of the tick ISR. */ diff --git a/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c b/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c index 2afe770b4b..46f99a5e7d 100644 --- a/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c +++ b/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c @@ -25,6 +25,7 @@ #include #include #include +#include #if SIMSPARC_FAST_IDLE==1 #define CLOCK_DRIVER_USE_FAST_IDLE 1 @@ -44,24 +45,34 @@ extern int CLOCK_SPEED; -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) +static rtems_timecounter_simple erc32_tc; + +static uint32_t erc32_tc_get( rtems_timecounter_simple *tc ) +{ + return ERC32_MEC.Real_Time_Clock_Counter; +} + +static bool erc32_tc_is_pending( rtems_timecounter_simple *tc ) +{ + return ERC32_Is_interrupt_pending( ERC32_INTERRUPT_REAL_TIME_CLOCK ); +} + +static uint32_t erc32_tc_get_timecount( struct timecounter *tc ) { - uint32_t clicks; - uint32_t usecs; - - clicks = ERC32_MEC.Real_Time_Clock_Counter; - - if ( ERC32_Is_interrupt_pending( ERC32_INTERRUPT_REAL_TIME_CLOCK ) ) { - clicks = ERC32_MEC.Real_Time_Clock_Counter; - usecs = (2*rtems_configuration_get_microseconds_per_tick() - clicks); - } else { - usecs = (rtems_configuration_get_microseconds_per_tick() - clicks); - } - return usecs * 1000; + return rtems_timecounter_simple_downcounter_get( + tc, + erc32_tc_get, + erc32_tc_is_pending + ); } -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick +static void erc32_tc_tick( void ) +{ + rtems_timecounter_simple_downcounter_tick( + &erc32_tc, + erc32_tc_get + ); +} static CPU_Counter_ticks erc32_counter_difference( CPU_Counter_ticks second, @@ -75,6 +86,7 @@ static CPU_Counter_ticks erc32_counter_difference( #define Clock_driver_support_initialize_hardware() \ do { \ + uint32_t frequency = 1000000; \ /* approximately 1 us per countdown */ \ ERC32_MEC.Real_Time_Clock_Scalar = CLOCK_SPEED - 1; \ ERC32_MEC.Real_Time_Clock_Counter = \ @@ -89,14 +101,22 @@ static CPU_Counter_ticks erc32_counter_difference( ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \ ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \ ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO \ + ); \ + rtems_timecounter_simple_install( \ + &erc32_tc, \ + frequency, \ + rtems_configuration_get_microseconds_per_tick(), \ + erc32_tc_get_timecount \ ); \ _SPARC_Counter_initialize( \ &ERC32_MEC.Real_Time_Clock_Counter, \ erc32_counter_difference \ ); \ - rtems_counter_initialize_converter(1000000); \ + rtems_counter_initialize_converter( frequency ); \ } while (0) +#define Clock_driver_timecounter_tick() erc32_tc_tick() + #define Clock_driver_support_shutdown_hardware() \ do { \ ERC32_Mask_interrupt( ERC32_INTERRUPT_REAL_TIME_CLOCK ); \ diff --git a/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c b/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c index ab4efa0e8a..3dd68e080a 100644 --- a/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c +++ b/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c @@ -24,11 +24,38 @@ #include #include +#include #if SIMSPARC_FAST_IDLE==1 #define CLOCK_DRIVER_USE_FAST_IDLE 1 #endif +static rtems_timecounter_simple leon2_tc; + +static uint32_t leon2_tc_get( rtems_timecounter_simple *tc ) +{ + return LEON_REG.Timer_Counter_1; +} + +static bool leon2_tc_is_pending( rtems_timecounter_simple *tc ) +{ + return LEON_Is_interrupt_pending( LEON_INTERRUPT_TIMER1 ); +} + +static uint32_t leon2_tc_get_timecount( struct timecounter *tc ) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + leon2_tc_get, + leon2_tc_is_pending + ); +} + +static void leon2_tc_tick( void ) +{ + rtems_timecounter_simple_downcounter_tick( &leon2_tc, leon2_tc_get ); +} + /* * The Real Time Clock Counter Timer uses this trap type. */ @@ -54,6 +81,12 @@ extern int CLOCK_SPEED; LEON_REG_TIMER_COUNTER_RELOAD_AT_ZERO | \ LEON_REG_TIMER_COUNTER_LOAD_COUNTER \ ); \ + rtems_timecounter_simple_install( \ + &leon2_tc, \ + 1000000, \ + rtems_configuration_get_microseconds_per_tick(), \ + leon2_tc_get_timecount \ + ); \ } while (0) #define Clock_driver_support_shutdown_hardware() \ @@ -62,23 +95,6 @@ extern int CLOCK_SPEED; LEON_REG.Timer_Control_1 = 0; \ } while (0) -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) -{ - uint32_t clicks; - uint32_t usecs; - - clicks = LEON_REG.Timer_Counter_1; - - if ( LEON_Is_interrupt_pending( LEON_INTERRUPT_TIMER1 ) ) { - clicks = LEON_REG.Timer_Counter_1; - usecs = (2*rtems_configuration_get_microseconds_per_tick() - clicks); - } else { - usecs = (rtems_configuration_get_microseconds_per_tick() - clicks); - } - return usecs * 1000; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick +#define Clock_driver_timecounter_tick() leon2_tc_tick() #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c b/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c index ad226161bc..b82b457866 100644 --- a/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c +++ b/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c @@ -24,6 +24,7 @@ #include #include #include +#include /* The LEON3 BSP Timer driver can rely on the Driver Manager if the * DrvMgr is initialized during startup. Otherwise the classic driver @@ -40,6 +41,43 @@ /* LEON3 Timer system interrupt number */ static int clkirq; +static bool leon3_tc_use_irqmp; + +static rtems_timecounter_simple leon3_tc; + +static uint32_t leon3_tc_get(rtems_timecounter_simple *tc) +{ + return LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value; +} + +static bool leon3_tc_is_pending(rtems_timecounter_simple *tc) +{ + return LEON_Is_interrupt_pending(clkirq); +} + +static uint32_t leon3_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + leon3_tc_get, + leon3_tc_is_pending + ); +} + +static uint32_t leon3_tc_get_timecount_irqmp(struct timecounter *tc) +{ + return LEON3_IrqCtrl_Regs->timestamp[0].counter; +} + +static void leon3_tc_tick(void) +{ + if (leon3_tc_use_irqmp) { + rtems_timecounter_tick(); + } else { + rtems_timecounter_simple_downcounter_tick(&leon3_tc, leon3_tc_get); + } +} + static void leon3_clock_profiling_interrupt_delay(void) { #ifdef RTEMS_PROFILING @@ -112,15 +150,36 @@ static void bsp_clock_handler_install(rtems_isr *new) } } +static void leon3_clock_initialize(void) +{ + volatile struct irqmp_timestamp_regs *irqmp_ts = + &LEON3_IrqCtrl_Regs->timestamp[0]; + + LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].reload = + rtems_configuration_get_microseconds_per_tick() - 1; + LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = + GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS | + GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE; + + if (leon3_irqmp_has_timestamp(irqmp_ts)) { + leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_irqmp; + leon3_tc.tc.tc_counter_mask = 0xffffffff; + leon3_tc.tc.tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev); + leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + leon3_tc_use_irqmp = true; + rtems_timecounter_install(&leon3_tc.tc); + } else { + rtems_timecounter_simple_install( + &leon3_tc, + LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER, + rtems_configuration_get_microseconds_per_tick(), + leon3_tc_get_timecount + ); + } +} + #define Clock_driver_support_initialize_hardware() \ - do { \ - LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].reload = \ - rtems_configuration_get_microseconds_per_tick() - 1; \ - \ - LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = \ - GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS | \ - GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE; \ - } while (0) + leon3_clock_initialize() #define Clock_driver_support_shutdown_hardware() \ do { \ @@ -128,27 +187,7 @@ static void bsp_clock_handler_install(rtems_isr *new) LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = 0; \ } while (0) -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) -{ - uint32_t clicks; - uint32_t usecs; - - if ( !LEON3_Timer_Regs ) - return 0; - - clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value; - - if ( LEON_Is_interrupt_pending( clkirq ) ) { - clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value; - usecs = (2*rtems_configuration_get_microseconds_per_tick() - clicks); - } else { - usecs = (rtems_configuration_get_microseconds_per_tick() - clicks); - } - return usecs * 1000; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick +#define Clock_driver_timecounter_tick() leon3_tc_tick() #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/sparc64/shared/clock/ckinit.c b/c/src/lib/libbsp/sparc64/shared/clock/ckinit.c index a3f9450174..ff0464c8f2 100644 --- a/c/src/lib/libbsp/sparc64/shared/clock/ckinit.c +++ b/c/src/lib/libbsp/sparc64/shared/clock/ckinit.c @@ -114,5 +114,7 @@ static void Clock_driver_support_initialize_hardware(void) \ } while ( 0 ) +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../shared/clockdrv_shell.h" diff --git a/c/src/lib/libcpu/arm/at91rm9200/clock/clock.c b/c/src/lib/libcpu/arm/at91rm9200/clock/clock.c index 16cf145b37..42b85f3f98 100644 --- a/c/src/lib/libcpu/arm/at91rm9200/clock/clock.c +++ b/c/src/lib/libcpu/arm/at91rm9200/clock/clock.c @@ -22,8 +22,6 @@ #include #include -static unsigned long st_pimr_reload; - /** * Enables clock interrupt. * @@ -77,17 +75,16 @@ rtems_irq_connect_data clock_isr_data = { BSP_install_rtems_irq_handler(&clock_isr_data); \ } while(0) -uint16_t st_pimr_value; static void Clock_driver_support_initialize_hardware(void) { uint32_t st_str; int slck; + unsigned long value; /* the system timer is driven from SLCK */ slck = at91rm9200_get_slck(); - st_pimr_value = (((rtems_configuration_get_microseconds_per_tick() * slck) + + value = (((rtems_configuration_get_microseconds_per_tick() * slck) + (1000000/2))/ 1000000); - st_pimr_reload = st_pimr_value; /* read the status to clear the int */ st_str = ST_REG(ST_SR); @@ -97,21 +94,9 @@ static void Clock_driver_support_initialize_hardware(void) AIC_SMR_REG(AIC_SMR_SYSIRQ) = AIC_SMR_PRIOR(0x7); /* set the timer value */ - ST_REG(ST_PIMR) = st_pimr_reload; + ST_REG(ST_PIMR) = value; } -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) -{ - uint16_t slck_counts; - - slck_counts = st_pimr_value - st_pimr_reload; - return (rtems_configuration_get_microseconds_per_tick() * slck_counts * 1000) - / st_pimr_value; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick - #define Clock_driver_support_at_tick() \ do { \ uint32_t st_str; \ @@ -126,4 +111,6 @@ static void Clock_driver_support_shutdown_hardware( void ) BSP_remove_rtems_irq_handler(&clock_isr_data); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c b/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c index 02f5b8c5ea..e75fed8a9e 100644 --- a/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c +++ b/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c @@ -17,12 +17,39 @@ #include #include #include /* for printk */ +#include void Clock_isr(rtems_irq_hdl_param arg); static void clock_isr_on(const rtems_irq_connect_data *unused); static void clock_isr_off(const rtems_irq_connect_data *unused); static int clock_isr_is_on(const rtems_irq_connect_data *irq); +static rtems_timecounter_simple lpc22xx_tc; + +static uint32_t lpc22xx_tc_get(rtems_timecounter_simple *tc) +{ + return T0TC; +} + +static bool lpc22xx_tc_is_pending(rtems_timecounter_simple *tc) +{ + return (T0IR & 0x1) != 0; +} + +static uint32_t lpc22xx_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_upcounter_get( + tc, + lpc22xx_tc_get, + lpc22xx_tc_is_pending + ); +} + +static void lpc22xx_tc_tick(void) +{ + rtems_timecounter_simple_upcounter_tick(&lpc22xx_tc, lpc22xx_tc_get); +} + /* Replace the first value with the clock's interrupt name. */ rtems_irq_connect_data clock_isr_data = { .name = LPC22xx_INTERRUPT_TIMER0, @@ -74,9 +101,10 @@ rtems_irq_connect_data clock_isr_data = { */ #define Clock_driver_support_initialize_hardware() \ do { \ + uint32_t mask; \ /* disable and clear timer 0, set to */ \ T0TCR &= 0; \ - /* TC is incrementet on every pclk.*/ \ + /* TC is incremented on every pclk.*/ \ T0PC = 0; \ /* initialize the timer period and prescaler */ \ T0MR0 = ((LPC22xx_Fpclk/1000 * \ @@ -89,6 +117,13 @@ rtems_irq_connect_data clock_isr_data = { T0TCR = 1; \ /* enable interrupt, skyeye will check this*/ \ T0IR |= 0x01; \ + /* install timecounter */ \ + rtems_timecounter_simple_install( \ + &lpc22xx_tc, \ + LPC22xx_Fpclk, \ + T0MR0, \ + lpc22xx_tc_get_timecount \ + ); \ } while (0) /** @@ -104,20 +139,6 @@ rtems_irq_connect_data clock_isr_data = { BSP_remove_rtems_irq_handler(&clock_isr_data); \ } while (0) -static uint32_t bsp_clock_nanoseconds_since_last_tick(void) -{ - uint32_t clicks; - uint32_t microseconds; - - clicks = T0TC; /* T0TC is the 32bit time counter 0 */ - - microseconds = (rtems_configuration_get_microseconds_per_tick() - clicks); - return microseconds * 1000; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - bsp_clock_nanoseconds_since_last_tick - /** * Enables clock interrupt. * @@ -149,6 +170,8 @@ static int clock_isr_is_on(const rtems_irq_connect_data *irq) return T0IR & 0x01; /* MR0 mask */ } +#define Clock_driver_timecounter_tick() lpc22xx_tc_tick() + /* Make sure to include this, and only at the end of the file */ #include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libcpu/arm/mc9328mxl/clock/clockdrv.c b/c/src/lib/libcpu/arm/mc9328mxl/clock/clockdrv.c index 0c3ab5dd93..d5dc69c9a0 100644 --- a/c/src/lib/libcpu/arm/mc9328mxl/clock/clockdrv.c +++ b/c/src/lib/libcpu/arm/mc9328mxl/clock/clockdrv.c @@ -130,5 +130,8 @@ static int clock_isr_is_on(const rtems_irq_connect_data *irq) return MC9328MXL_TMR1_TCTL & MC9328MXL_TMR_TCTL_IRQEN; } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + /* Make sure to include this, and only at the end of the file */ + #include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libcpu/arm/pxa255/clock/clock.c b/c/src/lib/libcpu/arm/pxa255/clock/clock.c index 92d9b21d2b..69b684926c 100644 --- a/c/src/lib/libcpu/arm/pxa255/clock/clock.c +++ b/c/src/lib/libcpu/arm/pxa255/clock/clock.c @@ -116,4 +116,6 @@ static void Clock_driver_support_shutdown_hardware( void ) BSP_remove_rtems_irq_handler(&clock_isr_data); } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + #include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c b/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c index 519d3f850d..a92dc607a3 100644 --- a/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c +++ b/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c @@ -27,17 +27,6 @@ rtems_irq_connect_data clock_isr_data = { .isOn = clock_isr_is_on, }; -/** - * Return the nanoseconds since last tick - */ -static uint32_t clock_driver_get_nanoseconds_since_last_tick(void) -{ - return 0; -} - -#define Clock_driver_nanoseconds_since_last_tick \ - clock_driver_get_nanoseconds_since_last_tick - /** * When we get the clock interrupt * - clear the interrupt bit? @@ -74,6 +63,7 @@ static uint32_t clock_driver_get_nanoseconds_since_last_tick(void) do { \ uint32_t cr; \ uint32_t freq; \ + uint32_t mask; \ /* set MUX for Timer4 to 1/16 */ \ cr=rTCFG1 & 0xFFF0FFFF; \ rTCFG1=(cr | (3<<16)); \ @@ -131,5 +121,7 @@ static int clock_isr_is_on(const rtems_irq_connect_data *irq) return 1; } +#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + /* Make sure to include this, and only at the end of the file */ #include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c b/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c index 218828cf4a..41b10cb30d 100644 --- a/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c +++ b/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c @@ -29,6 +29,7 @@ #include #include /* for printk() */ #include +#include #include /* for CLOCK_DRIVER_USE_FAST_IDLE */ @@ -48,11 +49,12 @@ volatile uint32_t Clock_driver_ticks; */ static uint32_t Clock_Decrementer_value; -/* - * This is the value by which elapsed count down timer ticks are multiplied to - * give an elapsed duration in nanoseconds, left-shifted by 32 bits - */ -static uint64_t Clock_Decrementer_reference; +static struct timecounter Clock_TC; + +static uint32_t Clock_Get_timecount(struct timecounter *tc) +{ + return ppc_time_base(); +} void clockOff(void* unused) { @@ -94,16 +96,27 @@ void clockOn(void* unused) static void clockHandler(void) { #if (CLOCK_DRIVER_USE_FAST_IDLE == 1) - do { - rtems_clock_tick(); - } while ( + rtems_interrupt_level level; + uint32_t tb; + + rtems_interrupt_disable(level); + + tb = ppc_time_base(); + rtems_timecounter_tick(); + + while ( _Thread_Heir == _Thread_Executing && _Thread_Executing->Start.entry_point == (Thread_Entry) rtems_configuration_get_idle_task() - ); + ) { + tb += Clock_Decrementer_value; + ppc_set_time_base( tb ); + rtems_timecounter_tick(); + } + rtems_interrupt_enable(level); #else - rtems_clock_tick(); + rtems_timecounter_tick(); #endif } @@ -141,7 +154,6 @@ void clockIsr(void *unused) rtems_interrupt_enable(flags); Clock_driver_ticks += 1; - /* * Real Time Clock counter/timer is set to automatically reload. */ @@ -187,7 +199,6 @@ int clockIsOn(void* unused) return 0; } - /* * Clock_exit * @@ -199,53 +210,6 @@ void Clock_exit( void ) (void) BSP_disconnect_clock_handler (); } -static uint32_t Clock_driver_nanoseconds_since_last_tick(void) -{ - uint32_t clicks, tmp; - - PPC_Get_decrementer( clicks ); - - /* - * Multiply by 1000 here separately from below so we do not overflow - * and get a negative value. - */ - tmp = (Clock_Decrementer_value - clicks) * 1000; - tmp /= (BSP_bus_frequency/BSP_time_base_divisor); - - return tmp * 1000; -} - -static uint32_t Clock_driver_nanoseconds_since_last_tick_bookE(void) -{ - uint32_t clicks; - uint64_t c; - - PPC_Get_decrementer( clicks ); - c = Clock_Decrementer_value - clicks; - - /* - * Check whether a clock tick interrupt is pending and hence that the - * decrementer's wrapped. If it has, we'll compensate by returning a time one - * tick period longer. - * - * We have to check interrupt status after reading the decrementer. If we - * don't, we may miss an interrupt and read a wrapped decrementer value - * without compensating for it - */ - if ( _read_BOOKE_TSR() & BOOKE_TSR_DIS ) - { - /* - * Re-read the decrementer: The tick interrupt may have been - * generated and the decrementer wrapped during the time since we - * last read it and the time we checked the interrupt status - */ - PPC_Get_decrementer( clicks ); - c = (Clock_Decrementer_value - clicks) + Clock_Decrementer_value; - } - - return (uint32_t)((c * Clock_Decrementer_reference) >> 32); -} - /* * Clock_initialize * @@ -262,9 +226,6 @@ rtems_device_driver Clock_initialize( Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)* rtems_configuration_get_milliseconds_per_tick(); - Clock_Decrementer_reference = ((uint64_t)1000000U<<32)/ - (BSP_bus_frequency/BSP_time_base_divisor); - /* set the decrementer now, prior to installing the handler * so no interrupts will happen in a while. */ @@ -283,24 +244,14 @@ rtems_device_driver Clock_initialize( _write_BOOKE_TCR(tcr); rtems_interrupt_enable(l); - - /* - * Set the nanoseconds since last tick handler - */ - rtems_clock_set_nanoseconds_extension( - Clock_driver_nanoseconds_since_last_tick_bookE - ); - } - else - { - /* - * Set the nanoseconds since last tick handler - */ - rtems_clock_set_nanoseconds_extension( - Clock_driver_nanoseconds_since_last_tick - ); } + Clock_TC.tc_get_timecount = Clock_Get_timecount; + Clock_TC.tc_counter_mask = 0xffffffff; + Clock_TC.tc_frequency = (1000 * BSP_bus_frequency) / BSP_time_base_divisor; + Clock_TC.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&Clock_TC); + /* * If a decrementer exception was pending, it is cleared by * executing the default (nop) handler at this point; -- cgit v1.2.3 From a9c4f15dbe5d0db8727dc7a9c82fc9ffa00e8cb6 Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Tue, 5 May 2015 15:32:03 +0200 Subject: doc: Clarify SPARC floating point ABI --- doc/cpu_supplement/sparc.t | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/cpu_supplement/sparc.t b/doc/cpu_supplement/sparc.t index d21e9feef1..740643a4d3 100644 --- a/doc/cpu_supplement/sparc.t +++ b/doc/cpu_supplement/sparc.t @@ -425,10 +425,15 @@ f4, ... f30) f8, ... f28) @end itemize -The floating point status register (fpsr) specifies +The floating point status register (FSR) specifies the behavior of the floating point unit for rounding, contains its condition codes, version specification, and trap information. +According to the ABI all floating point registers and the floating point status +register (FSR) are volatile. Thus the floating point context of a thread is the +empty set. The rounding direction is a system global state and must not be +modified by threads. + A queue of the floating point instructions which have started execution but not yet completed is maintained. This queue is needed to support the multiple cycle nature of floating -- cgit v1.2.3 From 1c59cad4aa40238c1aa3085adf3d079114c077b8 Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Fri, 24 Apr 2015 16:05:50 +0200 Subject: sparc: Add support for sptests/spcontext01 Implement _CPU_Context_validate() and _CPU_Context_volatile_clobber(). Update #2270. --- cpukit/score/cpu/sparc/Makefile.am | 2 + cpukit/score/cpu/sparc/rtems/score/cpu.h | 12 +- cpukit/score/cpu/sparc/sparc-context-validate.S | 368 +++++++++++++++++++++ .../cpu/sparc/sparc-context-volatile-clobber.S | 156 +++++++++ 4 files changed, 528 insertions(+), 10 deletions(-) create mode 100644 cpukit/score/cpu/sparc/sparc-context-validate.S create mode 100644 cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am index c6ea1c3da9..8cf4f4a65a 100644 --- a/cpukit/score/cpu/sparc/Makefile.am +++ b/cpukit/score/cpu/sparc/Makefile.am @@ -11,6 +11,8 @@ include_rtems_score_HEADERS += rtems/score/cpuatomic.h noinst_LIBRARIES = libscorecpu.a libscorecpu_a_SOURCES = cpu.c cpu_asm.S +libscorecpu_a_SOURCES += sparc-context-volatile-clobber.S +libscorecpu_a_SOURCES += sparc-context-validate.S libscorecpu_a_SOURCES += sparc-counter.c libscorecpu_a_SOURCES += sparcv8-atomic.c libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h index 235b3652ac..64e87509b4 100644 --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h @@ -1216,17 +1216,9 @@ void _CPU_Context_restore_fp( Context_Control_fp **fp_context_ptr ); -static inline void _CPU_Context_volatile_clobber( uintptr_t pattern ) -{ - /* TODO */ -} +void _CPU_Context_volatile_clobber( uintptr_t pattern ); -static inline void _CPU_Context_validate( uintptr_t pattern ) -{ - while (1) { - /* TODO */ - } -} +void _CPU_Context_validate( uintptr_t pattern ); typedef struct { uint32_t trap; diff --git a/cpukit/score/cpu/sparc/sparc-context-validate.S b/cpukit/score/cpu/sparc/sparc-context-validate.S new file mode 100644 index 0000000000..0ee7177d73 --- /dev/null +++ b/cpukit/score/cpu/sparc/sparc-context-validate.S @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +#define FRAME_OFFSET_BUFFER (CPU_MINIMUM_STACK_FRAME_SIZE) +#define FRAME_OFFSET_L0 (FRAME_OFFSET_BUFFER + 0x04) +#define FRAME_OFFSET_L1 (FRAME_OFFSET_L0 + 0x04) +#define FRAME_OFFSET_L2 (FRAME_OFFSET_L1 + 0x04) +#define FRAME_OFFSET_L3 (FRAME_OFFSET_L2 + 0x04) +#define FRAME_OFFSET_L4 (FRAME_OFFSET_L3 + 0x04) +#define FRAME_OFFSET_L5 (FRAME_OFFSET_L4 + 0x04) +#define FRAME_OFFSET_L6 (FRAME_OFFSET_L5 + 0x04) +#define FRAME_OFFSET_L7 (FRAME_OFFSET_L6 + 0x04) +#define FRAME_OFFSET_I0 (FRAME_OFFSET_L7 + 0x04) +#define FRAME_OFFSET_I1 (FRAME_OFFSET_I0 + 0x04) +#define FRAME_OFFSET_I2 (FRAME_OFFSET_I1 + 0x04) +#define FRAME_OFFSET_I3 (FRAME_OFFSET_I2 + 0x04) +#define FRAME_OFFSET_I4 (FRAME_OFFSET_I3 + 0x04) +#define FRAME_OFFSET_I5 (FRAME_OFFSET_I4 + 0x04) +#define FRAME_OFFSET_I6 (FRAME_OFFSET_I5 + 0x04) +#define FRAME_OFFSET_I7 (FRAME_OFFSET_I6 + 0x04) +#define FRAME_OFFSET_SP (FRAME_OFFSET_I7 + 0x04) +#define FRAME_END (FRAME_OFFSET_SP + 0x04) +#define FRAME_SIZE \ + ((FRAME_END + CPU_STACK_ALIGNMENT - 1) & ~(CPU_STACK_ALIGNMENT - 1)) + +.macro check_register reg + sub %g1, 1, %g1 + cmp %g1, \reg + bne restore_registers + nop +.endm + +.macro check_float_register reg + sub %g1, 1, %g1 + st \reg, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], %o1 + cmp %g1, %o1 + bne restore_registers + nop +.endm + +.macro check_fsr_register reg + st \reg, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], %o1 + sub %g1, 1, %g1 + clr %g3 + sethi %hi(0xCF800000), %g3 + or %g3, %lo(0x0FFF), %g3 + and %g1, %g3, %g3 + and %o1, %g3, %o1 + cmp %o1, %g3 + bne restore_registers + nop +.endm + +.macro write_register reg + add %g1, 1, %g1 + mov %g1, \reg +.endm + +.macro write_float_register reg + add %g1, 1, %g1 + st %g1, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], \reg +.endm + +.macro write_fsr_register reg + st \reg, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], %o1 + add %g1, 1, %g1 + clr %g3 + + /* + * FSR is masked with undefined, reserved or system-specific values + * (e.g. FPU architecture version, FP queue). + */ + sethi %hi(0xCF800000), %g3 + or %g3, %lo(0x0FFF), %g3 + and %g1, %g3, %g3 + or %o1, %g3, %g3 + st %g3, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], \reg +.endm + + .align 4 + PUBLIC(_CPU_Context_validate) +SYM(_CPU_Context_validate): + + /* + * g2 checks if the Floating Point Unit in the Processor Status + * Register (PSR) is set. + */ + mov %psr, %g2 + sethi %hi(SPARC_PSR_EF_MASK), %g3 + and %g2, %g3, %g2 + + /* g1 is used to save the original pattern */ + mov %o0, %g1 + + /* g4 establishes window counter */ + clr %g4 + + add %sp, -FRAME_SIZE, %sp + + st %l0, [%sp + FRAME_OFFSET_L0] + st %l1, [%sp + FRAME_OFFSET_L1] + st %l2, [%sp + FRAME_OFFSET_L2] + st %l3, [%sp + FRAME_OFFSET_L3] + st %l4, [%sp + FRAME_OFFSET_L4] + st %l5, [%sp + FRAME_OFFSET_L5] + st %l6, [%sp + FRAME_OFFSET_L6] + st %l7, [%sp + FRAME_OFFSET_L7] + st %i0, [%sp + FRAME_OFFSET_I0] + st %i1, [%sp + FRAME_OFFSET_I1] + st %i2, [%sp + FRAME_OFFSET_I2] + st %i3, [%sp + FRAME_OFFSET_I3] + st %i4, [%sp + FRAME_OFFSET_I4] + st %i5, [%sp + FRAME_OFFSET_I5] + st %i6, [%sp + FRAME_OFFSET_I6] + st %i7, [%sp + FRAME_OFFSET_I7] + st %sp, [%sp + FRAME_OFFSET_SP] + + cmp %g4, 0 + bne write_locals_and_outputs + nop + be check_for_fp + nop + +new_check_cycle: + clr %g4 + sub %g1, 1, %g1 + + /* Write pattern values into registers */ + +check_for_fp: + cmp %g2, 0 + be write_y + nop + + write_fsr_register %fsr + write_float_register %f0 + write_float_register %f1 + write_float_register %f2 + write_float_register %f3 + write_float_register %f4 + write_float_register %f5 + write_float_register %f6 + write_float_register %f7 + write_float_register %f8 + write_float_register %f9 + write_float_register %f10 + write_float_register %f11 + write_float_register %f12 + write_float_register %f13 + write_float_register %f14 + write_float_register %f15 + write_float_register %f16 + write_float_register %f17 + write_float_register %f18 + write_float_register %f19 + write_float_register %f20 + write_float_register %f21 + write_float_register %f22 + write_float_register %f23 + write_float_register %f24 + write_float_register %f25 + write_float_register %f26 + write_float_register %f27 + write_float_register %f28 + write_float_register %f29 + write_float_register %f30 + write_float_register %f31 + +write_y: + write_register %y + + write_register %i0 + write_register %i1 + write_register %i2 + write_register %i3 + write_register %i4 + write_register %i5 + /* Don't write register $i6 => frame pointer */ + /* Don't write register $i7 => return address */ + b write_locals_and_outputs + nop + +switch_to_next_window: + save %sp, -FRAME_SIZE, %sp + +write_locals_and_outputs: + /* l0 is used as a scratch register */ + write_register %l1 + write_register %l2 + write_register %l3 + write_register %l4 + write_register %l5 + write_register %l6 + write_register %l7 + write_register %o1 + write_register %o2 + write_register %o3 + write_register %o4 + write_register %o5 + /* Don't write register $o6 => stack pointer */ + /* Don't write register $o7 => return address */ + + add %g4, 1, %g4 + cmp %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS + bne switch_to_next_window + nop + + /* Dummy increment to set up reverse mechanism for checking process */ + add %g1, 1, %g1 + clr %g4 + + /* Checking begins here */ +window_checking: + cmp %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS + be y_checking + nop + +further_checking: + cmp %g4, 0 + bne goto_local_registers + nop + + /* Check normal registers */ + check_register %o5 + check_register %o4 + check_register %o3 + check_register %o2 + check_register %o1 + +goto_local_registers: + check_register %l7 + check_register %l6 + check_register %l5 + check_register %l4 + check_register %l3 + check_register %l2 + check_register %l1 + + check_register %i5 + check_register %i4 + check_register %i3 + check_register %i2 + check_register %i1 + /* + For the last window i0 also needs to be checked as this variable + is not overwritten by the outputs of another window. + */ + add %g4, 1, %g4 + cmp %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS + bne dont_check_i0 + nop + check_register %i0 + b y_checking + nop + +dont_check_i0: + restore + + ba window_checking + nop + + /* Check Y register */ +y_checking: + mov %y, %o1 + check_register %o1 + cmp %g2, 0 + be new_check_cycle + nop + + /* Check floating point registers */ + check_float_register %f31 + check_float_register %f30 + check_float_register %f29 + check_float_register %f28 + check_float_register %f27 + check_float_register %f26 + check_float_register %f25 + check_float_register %f24 + check_float_register %f23 + check_float_register %f22 + check_float_register %f21 + check_float_register %f20 + check_float_register %f19 + check_float_register %f18 + check_float_register %f17 + check_float_register %f16 + check_float_register %f15 + check_float_register %f14 + check_float_register %f13 + check_float_register %f12 + check_float_register %f11 + check_float_register %f10 + check_float_register %f9 + check_float_register %f8 + check_float_register %f7 + check_float_register %f6 + check_float_register %f5 + check_float_register %f4 + check_float_register %f3 + check_float_register %f2 + check_float_register %f1 + check_float_register %f0 + check_fsr_register %fsr + + be new_check_cycle + nop + + /****** RESTORE STARTS HERE *******/ + + /* Restore non-volatile registers */ + +restore_registers: + and %g4, (SPARC_NUMBER_OF_REGISTER_WINDOWS - 1), %g4 + cmp %g4, 0 + be real_restore + nop + restore + sub %g4, 1, %g4 + bne restore_registers + nop + +real_restore: + ld [%sp + FRAME_OFFSET_L0], %l0 + ld [%sp + FRAME_OFFSET_L1], %l1 + ld [%sp + FRAME_OFFSET_L2], %l2 + ld [%sp + FRAME_OFFSET_L3], %l3 + ld [%sp + FRAME_OFFSET_L4], %l4 + ld [%sp + FRAME_OFFSET_L5], %l5 + ld [%sp + FRAME_OFFSET_L6], %l6 + ld [%sp + FRAME_OFFSET_L7], %l7 + ld [%sp + FRAME_OFFSET_I0], %i0 + ld [%sp + FRAME_OFFSET_I1], %i1 + ld [%sp + FRAME_OFFSET_I2], %i2 + ld [%sp + FRAME_OFFSET_I3], %i3 + ld [%sp + FRAME_OFFSET_I4], %i4 + ld [%sp + FRAME_OFFSET_I5], %i5 + ld [%sp + FRAME_OFFSET_I6], %i6 + ld [%sp + FRAME_OFFSET_I7], %i7 + + sub %sp, -FRAME_SIZE, %sp + +return_value: + /* Load callback address and jump back */ + jmp %o7 + 8 + add %sp, FRAME_SIZE, %sp diff --git a/cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S b/cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S new file mode 100644 index 0000000000..6e364cd3f6 --- /dev/null +++ b/cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +#define SCRATCH_0 (CPU_MINIMUM_STACK_FRAME_SIZE) +#define SCRATCH_1 (SCRATCH_0 + 0x04) +#define FRAME_END (SCRATCH_1 + 0x04) +#define FRAME_SIZE \ + ((FRAME_END + CPU_STACK_ALIGNMENT - 1) & ~(CPU_STACK_ALIGNMENT - 1)) + +.macro clobber_register reg + sub %g2, 1, %g2 + mov %g2, \reg +.endm + +.macro clobber_fp_register reg + sub %g2, 1, %g2 + st %g2, [%sp + SCRATCH_0] + ld [%sp + SCRATCH_0], \reg +.endm + + .section ".bss" + .align 4 + + /* + * Use a global variable to vary the clobbered windows in each + * invocation to test the window overflow and underflow conditions. + */ +window_clobber_count: + .skip 4 + + .section ".text" + .align 4 + + PUBLIC(_CPU_Context_volatile_clobber) +SYM(_CPU_Context_volatile_clobber): + + /* Increment number of flushed windows by one */ + sethi %hi(window_clobber_count), %o1 + ld [%o1 + %lo(window_clobber_count)], %o2 + add %o2, 1, %o2 + st %o2, [%o1 + %lo(window_clobber_count)] + + /* Clear window counter number */ + clr %g1 + + /* Save pattern to global register */ + mov %o0, %g2 + +window_clobber: + + /* Switch window */ + + save %sp, -FRAME_SIZE, %sp + + /* Check how many windows shall be flushed */ + sethi %hi(window_clobber_count), %o1 + ld [%o1 + %lo(window_clobber_count)], %o2 + st %o2, [%o1 + %lo(window_clobber_count)] + and %o2, (SPARC_NUMBER_OF_REGISTER_WINDOWS - 1), %o1 + cmp %o1, 0 + bne no_manual_update + nop + add %o1, SPARC_NUMBER_OF_REGISTER_WINDOWS, %o1 + +no_manual_update: + /* Register to determine whether FPU is switched on */ + mov %psr, %o2 + sethi %hi(SPARC_PSR_EF_MASK), %o3 + and %o3, %o2, %o2 + + clobber_register %o3 + clobber_register %o4 + clobber_register %o5 + /* Don't overwrite return address $o7 */ + clobber_register %g3 + clobber_register %g4 + clobber_register %y + + cmp %o2, 0 + be window_update_check + nop + + clobber_fp_register %f0 + clobber_fp_register %f1 + clobber_fp_register %f2 + clobber_fp_register %f3 + clobber_fp_register %f4 + clobber_fp_register %f5 + clobber_fp_register %f6 + clobber_fp_register %f7 + clobber_fp_register %f8 + clobber_fp_register %f9 + clobber_fp_register %f10 + clobber_fp_register %f11 + clobber_fp_register %f12 + clobber_fp_register %f13 + clobber_fp_register %f14 + clobber_fp_register %f15 + clobber_fp_register %f16 + clobber_fp_register %f17 + clobber_fp_register %f18 + clobber_fp_register %f19 + clobber_fp_register %f20 + clobber_fp_register %f21 + clobber_fp_register %f22 + clobber_fp_register %f23 + clobber_fp_register %f24 + clobber_fp_register %f25 + clobber_fp_register %f26 + clobber_fp_register %f27 + clobber_fp_register %f28 + clobber_fp_register %f29 + clobber_fp_register %f30 + clobber_fp_register %f31 + +window_update_check: + + /* Counter to how many windows were switched */ + add %g1, 1, %g1 + cmp %g1, %o1 + bl window_clobber + nop + +restore_check: + + cmp %g1, 0 + be clobber_return + nop + + restore + sub %g1, 1, %g1 + ba restore_check + nop + +clobber_return: + + jmp %o7 + 8 + add %sp, FRAME_SIZE, %sp -- cgit v1.2.3 From 95889465e85dc38279f89559b5d88af00616ae4a Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 21 May 2015 17:27:34 +0200 Subject: bsp/tms570: Typo --- c/src/lib/libbsp/arm/tms570/clock/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/src/lib/libbsp/arm/tms570/clock/clock.c b/c/src/lib/libbsp/arm/tms570/clock/clock.c index d438a3da34..98ee5d9911 100644 --- a/c/src/lib/libbsp/arm/tms570/clock/clock.c +++ b/c/src/lib/libbsp/arm/tms570/clock/clock.c @@ -34,7 +34,7 @@ static struct timecounter tms570_rti_tc; -static uint32_t tms570_rti_get_timecount(struct timecounter tc) +static uint32_t tms570_rti_get_timecount(struct timecounter *tc) { return TMS570_RTI.RTIFRC0; } -- cgit v1.2.3 From bb997dd9c25cd8b577cf7782d239e4331e26ab40 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 20 May 2015 10:08:00 -0700 Subject: simsh1-testsuite.tcfg: Add fileio --- c/src/lib/libbsp/sh/shsim/make/custom/simsh1-testsuite.tcfg | 1 + 1 file changed, 1 insertion(+) diff --git a/c/src/lib/libbsp/sh/shsim/make/custom/simsh1-testsuite.tcfg b/c/src/lib/libbsp/sh/shsim/make/custom/simsh1-testsuite.tcfg index b83b7ee208..542f689e34 100644 --- a/c/src/lib/libbsp/sh/shsim/make/custom/simsh1-testsuite.tcfg +++ b/c/src/lib/libbsp/sh/shsim/make/custom/simsh1-testsuite.tcfg @@ -7,6 +7,7 @@ include: testdata/require-tick-isr.tcfg include: testdata/disable-intrcritical-tests.tcfg +fileio fsdosfsname01 iostream utf8proc01 -- cgit v1.2.3 From 22e576dfde41fdc76fac278f1e28450355c3ded1 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 20 May 2015 10:08:15 -0700 Subject: simsh2e-testsuite.tcfg: Add fileio --- c/src/lib/libbsp/sh/shsim/make/custom/simsh2e-testsuite.tcfg | 1 + 1 file changed, 1 insertion(+) diff --git a/c/src/lib/libbsp/sh/shsim/make/custom/simsh2e-testsuite.tcfg b/c/src/lib/libbsp/sh/shsim/make/custom/simsh2e-testsuite.tcfg index 33a87eaf6d..9ecaa70db4 100644 --- a/c/src/lib/libbsp/sh/shsim/make/custom/simsh2e-testsuite.tcfg +++ b/c/src/lib/libbsp/sh/shsim/make/custom/simsh2e-testsuite.tcfg @@ -6,6 +6,7 @@ include: testdata/require-tick-isr.tcfg include: testdata/disable-intrcritical-tests.tcfg +fileio fsdosfsname01 iostream utf8proc01 -- cgit v1.2.3 From 64f7724bd0a3ffb991d95c2f6c78a1d38dd0ec25 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 20 May 2015 10:08:53 -0700 Subject: Top files: Update and prep for release branch --- README | 15 +++++++++------ SUPPORT | 18 ------------------ VERSION | 5 ----- 3 files changed, 9 insertions(+), 29 deletions(-) delete mode 100644 SUPPORT delete mode 100644 VERSION diff --git a/README b/README index fc4a129e21..88a4999f20 100644 --- a/README +++ b/README @@ -6,16 +6,19 @@ http://rtems.org/onlinedocs/doc-current/share/rtems/html/ and released builds at http://www.rtems.org/onlinedocs/releases/ for information on building, installing, and using RTEMS. The INSTALL file tells you to come back here. -See the RTEMS Wiki at http://wiki.rtems.org/wiki/index.php/Main_Page -for community knowledge and tutorials. +See the RTEMS Wiki at http://devel.rtems.org for community knowledge and +tutorials. RTEMS Doxygen available at http://www.rtems.org/onlinedocs/doxygen/cpukit/html -Get help on the mailing lists: +The RTEMS Project maintains mailing lists which are used for most +discussions: + * For general-purpose questions related to using RTEMS, use the - rtems-users ml: http://www.rtems.org/mailman/listinfo/rtems-users + rtems-users ml: https://lists.rtems.org/mailman/listinfo/users * For questions and discussion related to development of RTEMS, use the - rtems-devel ml: http://www.rtems.org/mailman/listinfo/rtems-devel + rtems-devel ml: https://lists.rtems.org/mailman/listinfo/devel -See http://www.rtems.org/bugzilla/ to report a bug. +See https://devel.rtems.org/ to view existing or file a new issue +report ticket. diff --git a/SUPPORT b/SUPPORT deleted file mode 100644 index a3ab534660..0000000000 --- a/SUPPORT +++ /dev/null @@ -1,18 +0,0 @@ -On-Line Applications Research Corporation (OAR) offers support, -customization, and training for RTEMS. Custom RTEMS development services -includes porting RTEMS to new processors and the development of custom board -support packages and device drivers. In addition, OAR is available -to assist in the development of your real-time embedded application. - -For more information, email Joel Sherrill joel.sherrill@OARcorp.com -or contact OAR at: - -On-Line Applications Research Corporation -7047 Old Madison Pike Suite 320 -Huntsville AL 35806 -Voice: (256) 722-9985 -Fax: (256) 722-0985 - -RTEMS maintenance and development is funded solely by RTEMS users. -The future of RTEMS depends on its user base. - diff --git a/VERSION b/VERSION deleted file mode 100644 index 56a4f35499..0000000000 --- a/VERSION +++ /dev/null @@ -1,5 +0,0 @@ -# -# This file is automatically generated -- DO NOT EDIT!!! -# - -RTEMS Version 4.10.99.0 -- cgit v1.2.3 From 0afac6ab66359cf16fdb93de1a9203a254ce93fd Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 20 May 2015 10:11:41 -0700 Subject: Multiple bsp_specs: Change *(old_endfile) to %(old_endfile) Fix typo. closes 2345. --- c/src/lib/libbsp/arm/altera-cyclone-v/bsp_specs | 2 +- c/src/lib/libbsp/arm/beagle/bsp_specs | 2 +- c/src/lib/libbsp/arm/csb336/bsp_specs | 2 +- c/src/lib/libbsp/arm/csb337/bsp_specs | 2 +- c/src/lib/libbsp/arm/edb7312/bsp_specs | 2 +- c/src/lib/libbsp/arm/gba/bsp_specs | 2 +- c/src/lib/libbsp/arm/gdbarmsim/bsp_specs | 2 +- c/src/lib/libbsp/arm/gp32/bsp_specs | 2 +- c/src/lib/libbsp/arm/gumstix/bsp_specs | 2 +- c/src/lib/libbsp/arm/lm3s69xx/bsp_specs | 2 +- c/src/lib/libbsp/arm/lpc176x/bsp_specs | 2 +- c/src/lib/libbsp/arm/lpc24xx/bsp_specs | 2 +- c/src/lib/libbsp/arm/lpc32xx/bsp_specs | 2 +- c/src/lib/libbsp/arm/nds/bsp_specs | 2 +- c/src/lib/libbsp/arm/raspberrypi/bsp_specs | 2 +- c/src/lib/libbsp/arm/realview-pbx-a9/bsp_specs | 2 +- c/src/lib/libbsp/arm/rtl22xx/bsp_specs | 2 +- c/src/lib/libbsp/arm/smdk2410/bsp_specs | 2 +- c/src/lib/libbsp/arm/stm32f4/bsp_specs | 2 +- c/src/lib/libbsp/arm/tms570/bsp_specs | 2 +- c/src/lib/libbsp/arm/xilinx-zynq/bsp_specs | 2 +- c/src/lib/libbsp/bfin/TLL6527M/bsp_specs | 2 +- c/src/lib/libbsp/bfin/bf537Stamp/bsp_specs | 2 +- c/src/lib/libbsp/bfin/eZKit533/bsp_specs | 2 +- c/src/lib/libbsp/m32r/m32rsim/bsp_specs | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/bsp_specs b/c/src/lib/libbsp/arm/altera-cyclone-v/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/altera-cyclone-v/bsp_specs +++ b/c/src/lib/libbsp/arm/altera-cyclone-v/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/beagle/bsp_specs b/c/src/lib/libbsp/arm/beagle/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/beagle/bsp_specs +++ b/c/src/lib/libbsp/arm/beagle/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/csb336/bsp_specs b/c/src/lib/libbsp/arm/csb336/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/csb336/bsp_specs +++ b/c/src/lib/libbsp/arm/csb336/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/csb337/bsp_specs b/c/src/lib/libbsp/arm/csb337/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/csb337/bsp_specs +++ b/c/src/lib/libbsp/arm/csb337/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/edb7312/bsp_specs b/c/src/lib/libbsp/arm/edb7312/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/edb7312/bsp_specs +++ b/c/src/lib/libbsp/arm/edb7312/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/gba/bsp_specs b/c/src/lib/libbsp/arm/gba/bsp_specs index 5a51d82d2d..554ded6669 100644 --- a/c/src/lib/libbsp/arm/gba/bsp_specs +++ b/c/src/lib/libbsp/arm/gba/bsp_specs @@ -10,5 +10,5 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -Bstatic -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/gdbarmsim/bsp_specs b/c/src/lib/libbsp/arm/gdbarmsim/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/gdbarmsim/bsp_specs +++ b/c/src/lib/libbsp/arm/gdbarmsim/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/gp32/bsp_specs b/c/src/lib/libbsp/arm/gp32/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/gp32/bsp_specs +++ b/c/src/lib/libbsp/arm/gp32/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/gumstix/bsp_specs b/c/src/lib/libbsp/arm/gumstix/bsp_specs index 082653ad22..32c105fd0f 100755 --- a/c/src/lib/libbsp/arm/gumstix/bsp_specs +++ b/c/src/lib/libbsp/arm/gumstix/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/lm3s69xx/bsp_specs b/c/src/lib/libbsp/arm/lm3s69xx/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/lm3s69xx/bsp_specs +++ b/c/src/lib/libbsp/arm/lm3s69xx/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/lpc176x/bsp_specs b/c/src/lib/libbsp/arm/lpc176x/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/lpc176x/bsp_specs +++ b/c/src/lib/libbsp/arm/lpc176x/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/lpc24xx/bsp_specs b/c/src/lib/libbsp/arm/lpc24xx/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/bsp_specs +++ b/c/src/lib/libbsp/arm/lpc24xx/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/lpc32xx/bsp_specs b/c/src/lib/libbsp/arm/lpc32xx/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/bsp_specs +++ b/c/src/lib/libbsp/arm/lpc32xx/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/nds/bsp_specs b/c/src/lib/libbsp/arm/nds/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/nds/bsp_specs +++ b/c/src/lib/libbsp/arm/nds/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/raspberrypi/bsp_specs b/c/src/lib/libbsp/arm/raspberrypi/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/bsp_specs +++ b/c/src/lib/libbsp/arm/raspberrypi/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/realview-pbx-a9/bsp_specs b/c/src/lib/libbsp/arm/realview-pbx-a9/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/realview-pbx-a9/bsp_specs +++ b/c/src/lib/libbsp/arm/realview-pbx-a9/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/rtl22xx/bsp_specs b/c/src/lib/libbsp/arm/rtl22xx/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/rtl22xx/bsp_specs +++ b/c/src/lib/libbsp/arm/rtl22xx/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/smdk2410/bsp_specs b/c/src/lib/libbsp/arm/smdk2410/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/smdk2410/bsp_specs +++ b/c/src/lib/libbsp/arm/smdk2410/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/stm32f4/bsp_specs b/c/src/lib/libbsp/arm/stm32f4/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/stm32f4/bsp_specs +++ b/c/src/lib/libbsp/arm/stm32f4/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/tms570/bsp_specs b/c/src/lib/libbsp/arm/tms570/bsp_specs index 1afa2ba72e..86af12f071 100644 --- a/c/src/lib/libbsp/arm/tms570/bsp_specs +++ b/c/src/lib/libbsp/arm/tms570/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N -EB } *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/bsp_specs b/c/src/lib/libbsp/arm/xilinx-zynq/bsp_specs index 082653ad22..32c105fd0f 100644 --- a/c/src/lib/libbsp/arm/xilinx-zynq/bsp_specs +++ b/c/src/lib/libbsp/arm/xilinx-zynq/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/bfin/TLL6527M/bsp_specs b/c/src/lib/libbsp/bfin/TLL6527M/bsp_specs index 540acd1da9..32c5f572cc 100644 --- a/c/src/lib/libbsp/bfin/TLL6527M/bsp_specs +++ b/c/src/lib/libbsp/bfin/TLL6527M/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/bfin/bf537Stamp/bsp_specs b/c/src/lib/libbsp/bfin/bf537Stamp/bsp_specs index 540acd1da9..32c5f572cc 100644 --- a/c/src/lib/libbsp/bfin/bf537Stamp/bsp_specs +++ b/c/src/lib/libbsp/bfin/bf537Stamp/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/bfin/eZKit533/bsp_specs b/c/src/lib/libbsp/bfin/eZKit533/bsp_specs index 540acd1da9..32c5f572cc 100644 --- a/c/src/lib/libbsp/bfin/eZKit533/bsp_specs +++ b/c/src/lib/libbsp/bfin/eZKit533/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/m32r/m32rsim/bsp_specs b/c/src/lib/libbsp/m32r/m32rsim/bsp_specs index 559ebee5e0..3093175bb8 100644 --- a/c/src/lib/libbsp/m32r/m32rsim/bsp_specs +++ b/c/src/lib/libbsp/m32r/m32rsim/bsp_specs @@ -10,4 +10,4 @@ %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} *endfile: -%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtfini.o%s } +%{!qrtems: %(old_endfiles)} %{qrtems: crtend.o%s crtfini.o%s } -- cgit v1.2.3 From 1c0663b48f58432ec4ae5758e23b6cba540f96bd Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 20 May 2015 12:12:52 -0700 Subject: mcf52235-testsuite.tcfg: Add syscall01 --- c/src/lib/libbsp/m68k/mcf52235/make/custom/mcf52235-testsuite.tcfg | 1 + 1 file changed, 1 insertion(+) diff --git a/c/src/lib/libbsp/m68k/mcf52235/make/custom/mcf52235-testsuite.tcfg b/c/src/lib/libbsp/m68k/mcf52235/make/custom/mcf52235-testsuite.tcfg index 72153f716b..72deca158f 100644 --- a/c/src/lib/libbsp/m68k/mcf52235/make/custom/mcf52235-testsuite.tcfg +++ b/c/src/lib/libbsp/m68k/mcf52235/make/custom/mcf52235-testsuite.tcfg @@ -25,5 +25,6 @@ monitor02 paranoia pppd spstkalloc02 +syscall01 tmfine01 utf8proc01 -- cgit v1.2.3 From 221031ec9ffb329ec224056bf2672663113d9966 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 20 May 2015 15:02:19 -0700 Subject: kill_noposix.c: Remove obsolete __kill() --- cpukit/libcsupport/src/kill_noposix.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cpukit/libcsupport/src/kill_noposix.c b/cpukit/libcsupport/src/kill_noposix.c index cfc99f6218..3cb807c95e 100644 --- a/cpukit/libcsupport/src/kill_noposix.c +++ b/cpukit/libcsupport/src/kill_noposix.c @@ -9,7 +9,6 @@ * * + kill * + _kill_r - * + __kill * + sleep */ @@ -45,9 +44,4 @@ int _kill_r( struct _reent *ptr, pid_t pid, int sig ) return 0; } #endif - -int __kill( pid_t pid, int sig ) -{ - return 0; -} #endif -- cgit v1.2.3 From 52258f134452df13fa8ea6e4c0725607109a5e7b Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:51:01 -0700 Subject: arm/shared/lpc/clock/lpc-clock-config.c: Remove unused variable warning --- c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c b/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c index a55ba0e33c..0a0399939d 100644 --- a/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c +++ b/c/src/lib/libbsp/arm/shared/lpc/clock/lpc-clock-config.c @@ -67,7 +67,6 @@ static void lpc_clock_handler_install(void) static void lpc_clock_initialize(void) { - uint32_t mask; uint64_t interval = ((uint64_t) LPC_CLOCK_REFERENCE * (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000; -- cgit v1.2.3 From 5a9c3c105376c8d497fba6fcaf1f9e73c50dda13 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:51:36 -0700 Subject: pc386/clock/ckinit.c: Remove prototyped but not defined warning --- c/src/lib/libbsp/i386/pc386/clock/ckinit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c index 44a35bc6c1..04514d19fa 100644 --- a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c +++ b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c @@ -38,7 +38,6 @@ uint32_t pc386_clock_click_count; /* forward declaration */ void Clock_isr(void *param); -static void Clock_driver_support_at_tick_empty(void); static void clockOff(void); static void Clock_isr_handler(void *param); -- cgit v1.2.3 From 2a605f6495fe2ff5e8bd0733654bb63f6660b286 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:52:02 -0700 Subject: mcf52235/clock/clock.c: Remove unused variable warning --- c/src/lib/libbsp/m68k/mcf52235/clock/clock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c b/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c index 7a508a3b1c..fdc1ed6111 100644 --- a/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c +++ b/c/src/lib/libbsp/m68k/mcf52235/clock/clock.c @@ -68,7 +68,6 @@ static void Clock_driver_support_shutdown_hardware(void) */ static void Clock_driver_support_initialize_hardware(void) { - uint32_t mask; int level; uint32_t pmr; uint32_t preScaleCode = 0; -- cgit v1.2.3 From 4004d971faf071abc2072a9b4faecd9a32c753f8 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:52:21 -0700 Subject: mcf5225x/clock/clock.c: Remove unused variable warning --- c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c b/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c index 33fd76c0ae..743bd1ff94 100644 --- a/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c +++ b/c/src/lib/libbsp/m68k/mcf5225x/clock/clock.c @@ -68,7 +68,6 @@ static void Clock_driver_support_shutdown_hardware(void) */ static void Clock_driver_support_initialize_hardware(void) { - uint32_t mask; int level; uint32_t pmr; uint32_t preScaleCode = 0; -- cgit v1.2.3 From 68592d5432d357afb374d662dcfa84e6169b3979 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:53:41 -0700 Subject: mpc55xxevb/clock/clock-config.c: Remove unused variable warning --- c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c index 5724f9bf4b..4de9a520ab 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c @@ -86,7 +86,6 @@ static void mpc55xx_clock_handler_install(rtems_isr_entry isr) static void mpc55xx_clock_initialize(void) { - uint32_t mask; volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS; union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; @@ -208,7 +207,6 @@ static void mpc55xx_clock_handler_install(rtems_isr_entry isr) static void mpc55xx_clock_initialize(void) { - uint32_t mask; volatile PIT_RTI_CHANNEL_tag *channel = &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL]; uint64_t reference_clock = bsp_clock_speed; -- cgit v1.2.3 From efd351d2f8298f610ba1dff1adeb77ffb566572c Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:54:12 -0700 Subject: powerpc/shared/clock/clock.c: Remove unused variable warning --- c/src/lib/libbsp/powerpc/shared/clock/clock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libbsp/powerpc/shared/clock/clock.c b/c/src/lib/libbsp/powerpc/shared/clock/clock.c index d2f2d0d1b0..431488a901 100644 --- a/c/src/lib/libbsp/powerpc/shared/clock/clock.c +++ b/c/src/lib/libbsp/powerpc/shared/clock/clock.c @@ -185,7 +185,6 @@ rtems_device_driver Clock_initialize( uint64_t frequency = bsp_time_base_frequency; uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000); - uint32_t mask; /* * Set default ticker. -- cgit v1.2.3 From 562c1b1b6d30a5fc58864a980a39e2f3c318d032 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:54:35 -0700 Subject: arm/lpc22xx/clock/clockdrv.c: Remove unused variable warning --- c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c b/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c index e75fed8a9e..4887d2a8e0 100644 --- a/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c +++ b/c/src/lib/libcpu/arm/lpc22xx/clock/clockdrv.c @@ -101,7 +101,6 @@ rtems_irq_connect_data clock_isr_data = { */ #define Clock_driver_support_initialize_hardware() \ do { \ - uint32_t mask; \ /* disable and clear timer 0, set to */ \ T0TCR &= 0; \ /* TC is incremented on every pclk.*/ \ -- cgit v1.2.3 From 60e4c0094aaf242ae60ae530bcdb1f71d2b2b4a2 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:54:57 -0700 Subject: arm/s3c24xx/clock/clockdrv.c: Remove unused variable warning --- c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c b/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c index a92dc607a3..d8c7e644ad 100644 --- a/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c +++ b/c/src/lib/libcpu/arm/s3c24xx/clock/clockdrv.c @@ -63,7 +63,6 @@ rtems_irq_connect_data clock_isr_data = { do { \ uint32_t cr; \ uint32_t freq; \ - uint32_t mask; \ /* set MUX for Timer4 to 1/16 */ \ cr=rTCFG1 & 0xFFF0FFFF; \ rTCFG1=(cr | (3<<16)); \ -- cgit v1.2.3 From 63c68cfcafe3f070f377944d1370375783c8696e Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 21 May 2015 05:55:15 -0700 Subject: region*.c: Ensure return_status is set when RTEMS_MULTIPROCESSING is enabled --- cpukit/rtems/src/regiondelete.c | 1 - cpukit/rtems/src/regionextend.c | 1 - cpukit/rtems/src/regiongetfreeinfo.c | 1 - cpukit/rtems/src/regiongetinfo.c | 1 - cpukit/rtems/src/regiongetsegment.c | 1 - cpukit/rtems/src/regiongetsegmentsize.c | 1 - cpukit/rtems/src/regionresizesegment.c | 1 - cpukit/rtems/src/regionreturnsegment.c | 1 - 8 files changed, 8 deletions(-) diff --git a/cpukit/rtems/src/regiondelete.c b/cpukit/rtems/src/regiondelete.c index 5a2df7c009..b5209da890 100644 --- a/cpukit/rtems/src/regiondelete.c +++ b/cpukit/rtems/src/regiondelete.c @@ -52,7 +52,6 @@ rtems_status_code rtems_region_delete( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regionextend.c b/cpukit/rtems/src/regionextend.c index 65b68cdf1a..2ee2b992e4 100644 --- a/cpukit/rtems/src/regionextend.c +++ b/cpukit/rtems/src/regionextend.c @@ -65,7 +65,6 @@ rtems_status_code rtems_region_extend( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regiongetfreeinfo.c b/cpukit/rtems/src/regiongetfreeinfo.c index be0f0089a9..6ebd1abbd2 100644 --- a/cpukit/rtems/src/regiongetfreeinfo.c +++ b/cpukit/rtems/src/regiongetfreeinfo.c @@ -56,7 +56,6 @@ rtems_status_code rtems_region_get_free_information( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regiongetinfo.c b/cpukit/rtems/src/regiongetinfo.c index c3466f0566..d5eee727d3 100644 --- a/cpukit/rtems/src/regiongetinfo.c +++ b/cpukit/rtems/src/regiongetinfo.c @@ -50,7 +50,6 @@ rtems_status_code rtems_region_get_information( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regiongetsegment.c b/cpukit/rtems/src/regiongetsegment.c index 1e5c795697..26437b5188 100644 --- a/cpukit/rtems/src/regiongetsegment.c +++ b/cpukit/rtems/src/regiongetsegment.c @@ -100,7 +100,6 @@ rtems_status_code rtems_region_get_segment( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regiongetsegmentsize.c b/cpukit/rtems/src/regiongetsegmentsize.c index 8f823fcec9..ab07a56e9c 100644 --- a/cpukit/rtems/src/regiongetsegmentsize.c +++ b/cpukit/rtems/src/regiongetsegmentsize.c @@ -53,7 +53,6 @@ rtems_status_code rtems_region_get_segment_size( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regionresizesegment.c b/cpukit/rtems/src/regionresizesegment.c index ee3499a729..b1d9482c79 100644 --- a/cpukit/rtems/src/regionresizesegment.c +++ b/cpukit/rtems/src/regionresizesegment.c @@ -79,7 +79,6 @@ rtems_status_code rtems_region_resize_segment( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: diff --git a/cpukit/rtems/src/regionreturnsegment.c b/cpukit/rtems/src/regionreturnsegment.c index 6ae537fd4f..98f2240a23 100644 --- a/cpukit/rtems/src/regionreturnsegment.c +++ b/cpukit/rtems/src/regionreturnsegment.c @@ -82,7 +82,6 @@ rtems_status_code rtems_region_return_segment( #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ - break; #endif case OBJECTS_ERROR: -- cgit v1.2.3 From 66a5000d78bd5926c42d89fa1a5b2f15b074bfb6 Mon Sep 17 00:00:00 2001 From: Hesham ALMatary Date: Thu, 21 May 2015 17:52:56 +0100 Subject: cpukit: Add Epiphany architecture port v4 --- cpukit/configure.ac | 1 + cpukit/librpc/src/xdr/xdr_float.c | 1 + cpukit/score/cpu/Makefile.am | 1 + cpukit/score/cpu/epiphany/Makefile.am | 32 + cpukit/score/cpu/epiphany/cpu.c | 114 ++ .../cpu/epiphany/epiphany-context-initialize.c | 66 ++ .../score/cpu/epiphany/epiphany-context-switch.S | 216 ++++ .../cpu/epiphany/epiphany-exception-handler.S | 304 +++++ cpukit/score/cpu/epiphany/preinstall.am | 53 + cpukit/score/cpu/epiphany/rtems/asm.h | 120 ++ cpukit/score/cpu/epiphany/rtems/score/cpu.h | 1184 ++++++++++++++++++++ cpukit/score/cpu/epiphany/rtems/score/cpu_asm.h | 74 ++ cpukit/score/cpu/epiphany/rtems/score/cpuatomic.h | 14 + .../cpu/epiphany/rtems/score/epiphany-utility.h | 180 +++ cpukit/score/cpu/epiphany/rtems/score/epiphany.h | 64 ++ cpukit/score/cpu/epiphany/rtems/score/types.h | 68 ++ 16 files changed, 2492 insertions(+) create mode 100644 cpukit/score/cpu/epiphany/Makefile.am create mode 100644 cpukit/score/cpu/epiphany/cpu.c create mode 100644 cpukit/score/cpu/epiphany/epiphany-context-initialize.c create mode 100644 cpukit/score/cpu/epiphany/epiphany-context-switch.S create mode 100644 cpukit/score/cpu/epiphany/epiphany-exception-handler.S create mode 100644 cpukit/score/cpu/epiphany/preinstall.am create mode 100644 cpukit/score/cpu/epiphany/rtems/asm.h create mode 100644 cpukit/score/cpu/epiphany/rtems/score/cpu.h create mode 100644 cpukit/score/cpu/epiphany/rtems/score/cpu_asm.h create mode 100644 cpukit/score/cpu/epiphany/rtems/score/cpuatomic.h create mode 100644 cpukit/score/cpu/epiphany/rtems/score/epiphany-utility.h create mode 100644 cpukit/score/cpu/epiphany/rtems/score/epiphany.h create mode 100644 cpukit/score/cpu/epiphany/rtems/score/types.h diff --git a/cpukit/configure.ac b/cpukit/configure.ac index 2b432f6437..46942c9805 100644 --- a/cpukit/configure.ac +++ b/cpukit/configure.ac @@ -453,6 +453,7 @@ score/cpu/Makefile score/cpu/arm/Makefile score/cpu/bfin/Makefile score/cpu/avr/Makefile +score/cpu/epiphany/Makefile score/cpu/h8300/Makefile score/cpu/i386/Makefile score/cpu/lm32/Makefile diff --git a/cpukit/librpc/src/xdr/xdr_float.c b/cpukit/librpc/src/xdr/xdr_float.c index 925b29499f..ac8c46d49a 100644 --- a/cpukit/librpc/src/xdr/xdr_float.c +++ b/cpukit/librpc/src/xdr/xdr_float.c @@ -61,6 +61,7 @@ static char *rcsid = "$FreeBSD: src/lib/libc/xdr/xdr_float.c,v 1.7 1999/08/28 00 #if defined(__alpha__) || \ defined(_AM29K) || \ defined(__arm__) || \ + defined(__epiphany__) || defined(__EPIPHANY__) || \ defined(__H8300__) || defined(__h8300__) || \ defined(__hppa__) || \ defined(__i386__) || \ diff --git a/cpukit/score/cpu/Makefile.am b/cpukit/score/cpu/Makefile.am index 69abcd6cf6..7279d381f8 100644 --- a/cpukit/score/cpu/Makefile.am +++ b/cpukit/score/cpu/Makefile.am @@ -4,6 +4,7 @@ DIST_SUBDIRS = DIST_SUBDIRS += arm DIST_SUBDIRS += avr DIST_SUBDIRS += bfin +DIST_SUBDIRS += epiphany DIST_SUBDIRS += h8300 DIST_SUBDIRS += i386 DIST_SUBDIRS += lm32 diff --git a/cpukit/score/cpu/epiphany/Makefile.am b/cpukit/score/cpu/epiphany/Makefile.am new file mode 100644 index 0000000000..0099f081ca --- /dev/null +++ b/cpukit/score/cpu/epiphany/Makefile.am @@ -0,0 +1,32 @@ +include $(top_srcdir)/automake/compile.am + +CLEANFILES = +DISTCLEANFILES = + +include_rtemsdir = $(includedir)/rtems + +include_rtems_HEADERS = rtems/asm.h + +include_rtems_scoredir = $(includedir)/rtems/score + +include_rtems_score_HEADERS = +include_rtems_score_HEADERS += rtems/score/cpu.h +include_rtems_score_HEADERS += rtems/score/cpuatomic.h +include_rtems_score_HEADERS += rtems/score/cpu_asm.h +include_rtems_score_HEADERS += rtems/score/types.h +include_rtems_score_HEADERS += rtems/score/epiphany.h +include_rtems_score_HEADERS += rtems/score/epiphany-utility.h + +noinst_LIBRARIES = libscorecpu.a + +libscorecpu_a_SOURCES = cpu.c +libscorecpu_a_SOURCES += epiphany-exception-handler.S +libscorecpu_a_SOURCES += epiphany-context-switch.S +libscorecpu_a_SOURCES += epiphany-context-initialize.c + +libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) + +all-local: $(PREINSTALL_FILES) + +include $(srcdir)/preinstall.am +include $(top_srcdir)/automake/local.am diff --git a/cpukit/score/cpu/epiphany/cpu.c b/cpukit/score/cpu/epiphany/cpu.c new file mode 100644 index 0000000000..ada0f8c518 --- /dev/null +++ b/cpukit/score/cpu/epiphany/cpu.c @@ -0,0 +1,114 @@ +/* + * Epiphany CPU Dependent Source + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +void init(void); +void fini(void); + +void _init() +{ +} + +void _fini() +{ +} + +void _CPU_Exception_frame_print (const CPU_Exception_frame *ctx) +{ + /* Do nothing */ +} +/** + * @brief Performs processor dependent initialization. + */ +void _CPU_Initialize(void) +{ + /* Do nothing */ +} + +void _CPU_ISR_Set_level(uint32_t level) +{ + /* Do nothing */ +} + +uint32_t _CPU_ISR_Get_level( void ) +{ + /* Do nothing */ + return 0; +} + +void _CPU_ISR_install_raw_handler( + uint32_t vector, + proc_ptr new_handler, + proc_ptr *old_handler +) +{ + /* Do nothing */ +} + +void _CPU_ISR_install_vector( + uint32_t vector, + proc_ptr new_handler, + proc_ptr *old_handler +) +{ + /* Do nothing */ +} + +void _CPU_Install_interrupt_stack( void ) +{ + /* Do nothing */ +} + +CPU_Counter_ticks _CPU_Counter_read( void ) +{ + static CPU_Counter_ticks counter; + + CPU_Counter_ticks snapshot; + + snapshot = counter; + counter = snapshot + 1; + + return snapshot; +} + +void *_CPU_Thread_Idle_body( uintptr_t ignored ) +{ + do { + __asm__ __volatile__ ("idle"); + } while (1); + + return NULL; +} diff --git a/cpukit/score/cpu/epiphany/epiphany-context-initialize.c b/cpukit/score/cpu/epiphany/epiphany-context-initialize.c new file mode 100644 index 0000000000..b47871e4ab --- /dev/null +++ b/cpukit/score/cpu/epiphany/epiphany-context-initialize.c @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +#include +#include + +void _CPU_Context_Initialize( + Context_Control *context, + void *stack_area_begin, + size_t stack_area_size, + uint32_t new_level, + void (*entry_point)( void ), + bool is_fp, + void *tls_area +) +{ + uintptr_t stack = ((uintptr_t) stack_area_begin); + uint32_t sr, iret; + + /* Account for red-zone */ + uintptr_t stack_high = stack + stack_area_size - EPIPHANY_GCC_RED_ZONE_SIZE; + + asm volatile ("movfs %0, status \n" : "=r" (sr):); + asm volatile ("movfs %0, iret \n" : "=r" (iret):); + + memset(context, 0, sizeof(*context)); + + context->r[11] = stack_high; + context->r[13] = stack_high; + context->r[14] = (uintptr_t) entry_point; + context->status = sr; + context->iret = iret; +} diff --git a/cpukit/score/cpu/epiphany/epiphany-context-switch.S b/cpukit/score/cpu/epiphany/epiphany-context-switch.S new file mode 100644 index 0000000000..6d08389713 --- /dev/null +++ b/cpukit/score/cpu/epiphany/epiphany-context-switch.S @@ -0,0 +1,216 @@ +/* + * Epiphany CPU Dependent Source + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +.section .text,"ax" +.align 4 + +PUBLIC(_CPU_Context_switch) +PUBLIC(_CPU_Context_restore) +PUBLIC(_CPU_Context_restore_fp) +PUBLIC(_CPU_Context_save_fp) +PUBLIC(restore) + +SYM(_CPU_Context_switch): + /* Disable interrupts and store all registers */ + gid + + str r0, [r0] + str r1, [r0,1] + str r2, [r0,2] + str r3, [r0,3] + str r4, [r0,4] + str r5, [r0,5] + str r6, [r0,6] + str r7, [r0,7] + str r8, [r0,8] + str r9, [r0,9] + str r10, [r0,10] + str fp, [r0,11] + str r12, [r0,12] + str sp, [r0,13] + str lr, [r0,14] + str r15, [r0,15] + str r16, [r0,16] + str r17, [r0,17] + str r18, [r0,18] + str r19, [r0,19] + str r20, [r0,20] + str r21, [r0,21] + str r22, [r0,22] + str r23, [r0,23] + str r24, [r0,24] + str r25, [r0,25] + str r26, [r0,26] + str r27, [r0,27] + str r28, [r0,28] + str r29, [r0,29] + str r30, [r0,30] + str r31, [r0,31] + str r32, [r0,32] + str r33, [r0,33] + str r34, [r0,34] + str r35, [r0,35] + str r36, [r0,36] + str r37, [r0,37] + str r38, [r0,38] + str r39, [r0,39] + str r40, [r0,40] + str r41, [r0,41] + str r42, [r0,42] + str r43, [r0,43] + str r44, [r0,44] + str r45, [r0,45] + str r46, [r0,46] + str r47, [r0,47] + str r48, [r0,48] + str r49, [r0,49] + str r50, [r0,50] + str r51, [r0,51] + str r52, [r0,52] + str r53, [r0,53] + str r54, [r0,54] + str r55, [r0,55] + str r56, [r0,56] + str r57, [r0,57] + str r58, [r0,58] + str r59, [r0,59] + str r60, [r0,60] + str r61, [r0,61] + str r62, [r0,62] + str r63, [r0,63] + + /* Store status register */ + movfs r27, status + str r27, [r0,64] + + /* Store config register */ + movfs r27, config + str r27, [r0,65] + + /* Store interrupt return address register */ + movfs r27, iret + str r27, [r0,66] + +SYM(restore): + + /* r1 contains buffer address, skip it */ + ldr r2, [r1,2] + ldr r3, [r1,3] + ldr r4, [r1,4] + ldr r5, [r1,5] + ldr r6, [r1,6] + ldr r7, [r1,7] + ldr r8, [r1,8] + ldr r9, [r1,9] + ldr r10, [r1,10] + ldr fp, [r1,11] + ldr r12, [r1,12] + ldr sp, [r1,13] + ldr lr, [r1,14] + ldr r15, [r1,15] + ldr r16, [r1,16] + ldr r17, [r1,17] + ldr r18, [r1,18] + ldr r19, [r1,19] + ldr r20, [r1,20] + ldr r21, [r1,21] + ldr r22, [r1,22] + ldr r23, [r1,23] + ldr r24, [r1,24] + ldr r25, [r1,25] + ldr r26, [r1,26] + ldr r27, [r1,27] + ldr r32, [r1,32] + ldr r33, [r1,33] + ldr r34, [r1,34] + ldr r35, [r1,35] + ldr r36, [r1,36] + ldr r37, [r1,37] + ldr r38, [r1,38] + ldr r39, [r1,39] + ldr r40, [r1,40] + ldr r41, [r1,41] + ldr r42, [r1,42] + ldr r43, [r1,43] + ldr r44, [r1,44] + ldr r45, [r1,45] + ldr r46, [r1,46] + ldr r47, [r1,47] + ldr r48, [r1,48] + ldr r49, [r1,49] + ldr r50, [r1,50] + ldr r51, [r1,51] + ldr r52, [r1,52] + ldr r53, [r1,53] + ldr r54, [r1,54] + ldr r55, [r1,55] + ldr r56, [r1,56] + ldr r57, [r1,57] + ldr r58, [r1,58] + ldr r59, [r1,59] + ldr r60, [r1,60] + ldr r61, [r1,61] + ldr r62, [r1,62] + ldr r63, [r1,63] + + /* Load status register */ + ldr r0, [r1,64] + movts status, r0 + + /* Load config register */ + ldr r0, [r1,65] + movts config, r0 + + /* Load interrupt return address register */ + ldr r0,[r1,66] + movts iret, r0 + + ldr r0,[r1] + ldr r1,[r1,1] + + /* Enable interrupts and return */ + gie + jr lr + +SYM(_CPU_Context_restore): + mov r1, r0 + b _restore + nop + +/* No FP support for Epiphany yet */ +SYM(_CPU_Context_restore_fp): + nop + + SYM(_CPU_Context_save_fp): + nop diff --git a/cpukit/score/cpu/epiphany/epiphany-exception-handler.S b/cpukit/score/cpu/epiphany/epiphany-exception-handler.S new file mode 100644 index 0000000000..09c88fd861 --- /dev/null +++ b/cpukit/score/cpu/epiphany/epiphany-exception-handler.S @@ -0,0 +1,304 @@ +/** + * @file + * + * @ingroup ScoreCPU + * + * @brief Epiphany exception support implementation. + */ + +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +EXTERN(bsp_start_vector_table_begin) +EXTERN(_Thread_Dispatch) +PUBLIC(ISR_Handler) + +.section .text, "ax" +.align 4 +TYPE_FUNC(ISR_Handler) +SYM(ISR_Handler): + /* Reserve space for CPU_Exception_frame */ + sub sp, sp, #(CPU_EXCEPTION_FRAME_SIZE) + + str r0, [sp] + str r1, [sp,1] + str r2, [sp,2] + str r3, [sp,3] + str r4, [sp,4] + str r5, [sp,5] + str r6, [sp,6] + str r7, [sp,7] + str r8, [sp,8] + str r9, [sp,9] + str r10, [sp,10] + str fp, [sp,11] + str r12, [sp,12] + + /* Save interrupted task stack pointer */ + add r1, sp, #(CPU_EXCEPTION_FRAME_SIZE + 8) + str r1,[sp,13] + + str lr, [sp,14] + str r15, [sp,15] + str r16, [sp,16] + str r17, [sp,17] + str r18, [sp,18] + str r19, [sp,19] + str r20, [sp,20] + str r21, [sp,21] + str r22, [sp,22] + str r23, [sp,23] + str r24, [sp,24] + str r25, [sp,25] + str r26, [sp,26] + str r27, [sp,27] + str r28, [sp,28] + str r29, [sp,29] + str r30, [sp,30] + str r31, [sp,31] + str r32, [sp,32] + str r33, [sp,33] + str r34, [sp,34] + str r35, [sp,35] + str r36, [sp,36] + str r37, [sp,37] + str r38, [sp,38] + str r39, [sp,39] + str r40, [sp,40] + str r41, [sp,41] + str r42, [sp,42] + str r43, [sp,43] + str r44, [sp,44] + str r45, [sp,45] + str r46, [sp,46] + str r47, [sp,47] + str r48, [sp,48] + str r49, [sp,49] + str r50, [sp,50] + str r51, [sp,51] + str r52, [sp,52] + str r53, [sp,53] + str r54, [sp,54] + str r55, [sp,55] + str r56, [sp,56] + str r57, [sp,57] + str r58, [sp,58] + str r59, [sp,59] + str r60, [sp,60] + str r61, [sp,61] + /* r62 and r63 are saved from start.S interrupt entry + * and hold vector number and _ISR_Handler address repsectively. + */ + + /* Save status register */ + movfs r1,status + str r1, [sp,62] + + /* Save config register */ + movfs r1,config + str r1, [sp,63] + + /* Save interrupt return address register */ + movfs r1,iret + str r1, [sp,64] + + mov r33, %low(__Per_CPU_Information) + movt r33, %high(__Per_CPU_Information) + + add r6, r33, #(PER_CPU_ISR_NEST_LEVEL) + add r8, r33, #(PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL) + + /* Increment nesting level and disable thread dispatch */ + ldr r5, [r6] + ldr r7, [r8] + add r5, r5, #1 + add r7, r7, #1 + str r5, [r6] + str r7, [r8] + + /* Keep sp (Exception frame address) in r32 - Callee saved */ + mov r32, sp + + /* Keep __Per_CPU_Information address in r33 - Callee saved */ + mov r33, r18 + + /* Call the exception handler from vector table. + * First function arg for C handler is vector number, + * and the second is a pointer to exception frame. + */ + mov r0, r62 + mov r1, sp + + mov r27, r62 + lsl r27, r27, #2 + mov r26, %low(_bsp_start_vector_table_begin) + movt r15, #0 + add r27, r27, r26 + ldr r27, [r27] + + /* Do not switch stacks if we are in a nested interrupt. At + * this point r5 should be holding ISR_NEST_LEVEL value. + */ + sub r37, r5, #1 + bgtu jump_to_c_handler + + /* Switch to RTEMS dedicated interrupt stack */ + add sp, r18, #(PER_CPU_INTERRUPT_STACK_HIGH) + ldr sp, [sp] + +jump_to_c_handler: + jalr r27 + + /* Switch back to the interrupted task stack */ + mov sp, r32 + + /* Get the address of __Per_CPU_Information */ + mov r18, r33 + + /* Decrement nesting level and enable multitasking */ + add r6, r18, #(PER_CPU_ISR_NEST_LEVEL) + add r8, r18, #(PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL) + + ldr r5, [r6] + ldr r7, [r8] + sub r5, r5, #1 + sub r7, r7, #1 + str r5, [r6] + str r7, [r8] + + /* Check if _ISR_Nest_level > 0 */ + sub r37, r5, #0 + bgtu exception_frame_restore + + /* Check if _Thread_Dispatch_disable_level > 0 */ + sub r37, r7, #0 + bgtu exception_frame_restore + + /* Check if dispatch needed */ + add r31, r18, #(PER_CPU_DISPATCH_NEEDED) + ldr r31, [r31] + + sub r35, r31, #0 + beq exception_frame_restore + + mov r35, %low(__Thread_Dispatch) + movt r35, %high(__Thread_Dispatch) + jalr r35 + +exception_frame_restore: + + ldr r1, [sp,1] + ldr r2, [sp,2] + ldr r3, [sp,3] + ldr r4, [sp,4] + ldr r5, [sp,5] + ldr r6, [sp,6] + ldr r7, [sp,7] + ldr r8, [sp,8] + ldr r9, [sp,9] + ldr r10, [sp,10] + ldr fp, [sp,11] + ldr r12, [sp,12] + ldr lr, [sp,14] + ldr r15, [sp,15] + ldr r16, [sp,16] + ldr r17, [sp,17] + ldr r18, [sp,18] + ldr r19, [sp,19] + ldr r20, [sp,20] + ldr r21, [sp,21] + ldr r22, [sp,22] + ldr r23, [sp,23] + ldr r24, [sp,24] + ldr r25, [sp,25] + ldr r26, [sp,26] + ldr r27, [sp,27] + ldr r28, [sp,28] + ldr r29, [sp,29] + ldr r30, [sp,30] + ldr r31, [sp,31] + ldr r32, [sp,32] + ldr r34, [sp,34] + ldr r36, [sp,36] + ldr r38, [sp,38] + ldr r39, [sp,39] + ldr r40, [sp,40] + ldr r41, [sp,41] + ldr r42, [sp,42] + ldr r43, [sp,43] + ldr r44, [sp,44] + ldr r45, [sp,45] + ldr r46, [sp,46] + ldr r47, [sp,47] + ldr r48, [sp,48] + ldr r49, [sp,49] + ldr r50, [sp,50] + ldr r51, [sp,51] + ldr r52, [sp,52] + ldr r53, [sp,53] + ldr r54, [sp,54] + ldr r55, [sp,55] + ldr r56, [sp,56] + ldr r57, [sp,57] + ldr r58, [sp,58] + ldr r59, [sp,59] + ldr r60, [sp,60] + ldr r61, [sp,61] + + /* Restore status register */ + ldr r0,[sp,62] + movts status, r0 + + /* Restore config register */ + ldr r0, [sp,63] + movts config, r0 + + /* Restore interrupt return address register */ + ldr r0, [sp,64] + movts iret, r0 + + ldr r0,[sp] + + /* Restore interrupted task's stack pointer */ + ldr sp, [sp,13] + + /* r62 and r63 are saved from start.S interrupt entry + * and hold vector number and _ISR_Handler address repsectively. + */ + ldr r62, [sp, -8] + ldr r63, [sp, -4] + + /* return from interrupt */ + rti diff --git a/cpukit/score/cpu/epiphany/preinstall.am b/cpukit/score/cpu/epiphany/preinstall.am new file mode 100644 index 0000000000..0250d128ed --- /dev/null +++ b/cpukit/score/cpu/epiphany/preinstall.am @@ -0,0 +1,53 @@ +## Automatically generated by ampolish3 - Do not edit + +if AMPOLISH3 +$(srcdir)/preinstall.am: Makefile.am + $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am +endif + +PREINSTALL_DIRS = +DISTCLEANFILES += $(PREINSTALL_DIRS) + +all-am: $(PREINSTALL_FILES) + +PREINSTALL_FILES = +CLEANFILES += $(PREINSTALL_FILES) + +$(PROJECT_INCLUDE)/rtems/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems + @: > $(PROJECT_INCLUDE)/rtems/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/$(dirstamp) + +$(PROJECT_INCLUDE)/rtems/asm.h: rtems/asm.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/asm.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/asm.h + +$(PROJECT_INCLUDE)/rtems/score/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/score + @: > $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + +$(PROJECT_INCLUDE)/rtems/score/cpu.h: rtems/score/cpu.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpu.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpu.h + +$(PROJECT_INCLUDE)/rtems/score/cpuatomic.h: rtems/score/cpuatomic.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h + +$(PROJECT_INCLUDE)/rtems/score/cpu_asm.h: rtems/score/cpu_asm.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpu_asm.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpu_asm.h + +$(PROJECT_INCLUDE)/rtems/score/types.h: rtems/score/types.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/types.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/types.h + +$(PROJECT_INCLUDE)/rtems/score/epiphany.h: rtems/score/epiphany.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/epiphany.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/epiphany.h + +$(PROJECT_INCLUDE)/rtems/score/epiphany-utility.h: rtems/score/epiphany-utility.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/epiphany-utility.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/epiphany-utility.h + diff --git a/cpukit/score/cpu/epiphany/rtems/asm.h b/cpukit/score/cpu/epiphany/rtems/asm.h new file mode 100644 index 0000000000..87e0cca1cb --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/asm.h @@ -0,0 +1,120 @@ +/** + * @file rtems/asm.h + * + * This include file attempts to address the problems + * caused by incompatible flavors of assemblers and + * toolsets. It primarily addresses variations in the + * use of leading underscores on symbols and the requirement + * that register names be preceded by a %. + */ + +/* + * NOTE: The spacing in the use of these macros + * is critical to them working as advertised. + * + * This file is based on similar code found in newlib available + * from ftp.cygnus.com. The file which was used had no copyright + * notice. This file is freely distributable as long as the source + * of the file is noted. This file is: + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * + * COPYRIGHT (c) 1994-1997. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __EPIPHANY_ASM_H +#define __EPIPHANY_ASM_H + +/* + * Indicate we are in an assembly file and get the basic CPU definitions. + */ + +#ifndef ASM +#define ASM +#endif +#include +#include + +/* + * Recent versions of GNU cpp define variables which indicate the + * need for underscores and percents. If not using GNU cpp or + * the version does not support this, then you will obviously + * have to define these as appropriate. + */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* + * define macros for all of the registers on this CPU + * + * EXAMPLE: #define d0 REG (d0) + */ + +/* + * Define macros to handle section beginning and ends. + */ +#define BEGIN_CODE_DCL .text +#define END_CODE_DCL +#define BEGIN_DATA_DCL .data +#define END_DATA_DCL +#define BEGIN_CODE .text +#define END_CODE +#define BEGIN_DATA +#define END_DATA +#define BEGIN_BSS +#define END_BSS +#define END + +/* + * Following must be tailor for a particular flavor of the C compiler. + * They may need to put underscores in front of the symbols. + */ + +#define PUBLIC(sym) .global SYM (sym) +#define EXTERN(sym) .extern SYM (sym) +#define TYPE_FUNC(sym) .type SYM (sym), %function + +#endif diff --git a/cpukit/score/cpu/epiphany/rtems/score/cpu.h b/cpukit/score/cpu/epiphany/rtems/score/cpu.h new file mode 100644 index 0000000000..fb5e6b2966 --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/score/cpu.h @@ -0,0 +1,1184 @@ +/** + * @file rtems/score/cpu.h + */ + +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _EPIPHANY_CPU_H +#define _EPIPHANY_CPU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* pick up machine definitions */ +#include +#ifndef ASM +#include +#include +#include /* for printk */ +#endif + +/* conditional compilation parameters */ + +/* + * Should the calls to _Thread_Enable_dispatch be inlined? + * + * If TRUE, then they are inlined. + * If FALSE, then a subroutine call is made. + * + * Basically this is an example of the classic trade-off of size + * versus speed. Inlining the call (TRUE) typically increases the + * size of RTEMS while speeding up the enabling of dispatching. + * [NOTE: In general, the _Thread_Dispatch_disable_level will + * only be 0 or 1 unless you are in an interrupt handler and that + * interrupt handler invokes the executive.] When not inlined + * something calls _Thread_Enable_dispatch which in turns calls + * _Thread_Dispatch. If the enable dispatch is inlined, then + * one subroutine call is avoided entirely.] + * + */ + +#define CPU_INLINE_ENABLE_DISPATCH FALSE + +/* + * Should the body of the search loops in _Thread_queue_Enqueue_priority + * be unrolled one time? In unrolled each iteration of the loop examines + * two "nodes" on the chain being searched. Otherwise, only one node + * is examined per iteration. + * + * If TRUE, then the loops are unrolled. + * If FALSE, then the loops are not unrolled. + * + * The primary factor in making this decision is the cost of disabling + * and enabling interrupts (_ISR_Flash) versus the cost of rest of the + * body of the loop. On some CPUs, the flash is more expensive than + * one iteration of the loop body. In this case, it might be desirable + * to unroll the loop. It is important to note that on some CPUs, this + * code is the longest interrupt disable period in RTEMS. So it is + * necessary to strike a balance when setting this parameter. + * + */ + +#define CPU_UNROLL_ENQUEUE_PRIORITY TRUE + +/* + * Does RTEMS manage a dedicated interrupt stack in software? + * + * If TRUE, then a stack is allocated in _ISR_Handler_initialization. + * If FALSE, nothing is done. + * + * If the CPU supports a dedicated interrupt stack in hardware, + * then it is generally the responsibility of the BSP to allocate it + * and set it up. + * + * If the CPU does not support a dedicated interrupt stack, then + * the porter has two options: (1) execute interrupts on the + * stack of the interrupted task, and (2) have RTEMS manage a dedicated + * interrupt stack. + * + * If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE. + * + * Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and + * CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is + * possible that both are FALSE for a particular CPU. Although it + * is unclear what that would imply about the interrupt processing + * procedure on that CPU. + * + * Currently, for epiphany port, _ISR_Handler is responsible for switching to + * RTEMS dedicated interrupt task. + * + */ + +#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE + +/* + * Does this CPU have hardware support for a dedicated interrupt stack? + * + * If TRUE, then it must be installed during initialization. + * If FALSE, then no installation is performed. + * + * If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE. + * + * Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and + * CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is + * possible that both are FALSE for a particular CPU. Although it + * is unclear what that would imply about the interrupt processing + * procedure on that CPU. + * + */ + +#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE + +/* + * Does RTEMS allocate a dedicated interrupt stack in the Interrupt Manager? + * + * If TRUE, then the memory is allocated during initialization. + * If FALSE, then the memory is allocated during initialization. + * + * This should be TRUE is CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE + * or CPU_INSTALL_HARDWARE_INTERRUPT_STACK is TRUE. + * + */ + +#define CPU_ALLOCATE_INTERRUPT_STACK TRUE + +/* + * Does the RTEMS invoke the user's ISR with the vector number and + * a pointer to the saved interrupt frame (1) or just the vector + * number (0)? + * + */ + +#define CPU_ISR_PASSES_FRAME_POINTER 1 + +/* + * Does the CPU have hardware floating point? + * + * If TRUE, then the RTEMS_FLOATING_POINT task attribute is supported. + * If FALSE, then the RTEMS_FLOATING_POINT task attribute is ignored. + * + * If there is a FP coprocessor such as the i387 or mc68881, then + * the answer is TRUE. + * + * The macro name "epiphany_HAS_FPU" should be made CPU specific. + * It indicates whether or not this CPU model has FP support. For + * example, it would be possible to have an i386_nofp CPU model + * which set this to false to indicate that you have an i386 without + * an i387 and wish to leave floating point support out of RTEMS. + * + * The CPU_SOFTWARE_FP is used to indicate whether or not there + * is software implemented floating point that must be context + * switched. The determination of whether or not this applies + * is very tool specific and the state saved/restored is also + * compiler specific. + * + * epiphany Specific Information: + * + * At this time there are no implementations of Epiphany that are + * expected to implement floating point. + */ + +#define CPU_HARDWARE_FP FALSE +#define CPU_SOFTWARE_FP FALSE + +/* + * Are all tasks RTEMS_FLOATING_POINT tasks implicitly? + * + * If TRUE, then the RTEMS_FLOATING_POINT task attribute is assumed. + * If FALSE, then the RTEMS_FLOATING_POINT task attribute is followed. + * + * If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well. + * + */ + +#define CPU_ALL_TASKS_ARE_FP FALSE + +/* + * Should the IDLE task have a floating point context? + * + * If TRUE, then the IDLE task is created as a RTEMS_FLOATING_POINT task + * and it has a floating point context which is switched in and out. + * If FALSE, then the IDLE task does not have a floating point context. + * + * Setting this to TRUE negatively impacts the time required to preempt + * the IDLE task from an interrupt because the floating point context + * must be saved as part of the preemption. + * + */ + +#define CPU_IDLE_TASK_IS_FP FALSE + +/* + * Should the saving of the floating point registers be deferred + * until a context switch is made to another different floating point + * task? + * + * If TRUE, then the floating point context will not be stored until + * necessary. It will remain in the floating point registers and not + * disturned until another floating point task is switched to. + * + * If FALSE, then the floating point context is saved when a floating + * point task is switched out and restored when the next floating point + * task is restored. The state of the floating point registers between + * those two operations is not specified. + * + * If the floating point context does NOT have to be saved as part of + * interrupt dispatching, then it should be safe to set this to TRUE. + * + * Setting this flag to TRUE results in using a different algorithm + * for deciding when to save and restore the floating point context. + * The deferred FP switch algorithm minimizes the number of times + * the FP context is saved and restored. The FP context is not saved + * until a context switch is made to another, different FP task. + * Thus in a system with only one FP task, the FP context will never + * be saved or restored. + * + */ + +#define CPU_USE_DEFERRED_FP_SWITCH FALSE + +/* + * Does this port provide a CPU dependent IDLE task implementation? + * + * If TRUE, then the routine _CPU_Thread_Idle_body + * must be provided and is the default IDLE thread body instead of + * _CPU_Thread_Idle_body. + * + * If FALSE, then use the generic IDLE thread body if the BSP does + * not provide one. + * + * This is intended to allow for supporting processors which have + * a low power or idle mode. When the IDLE thread is executed, then + * the CPU can be powered down. + * + * The order of precedence for selecting the IDLE thread body is: + * + * 1. BSP provided + * 2. CPU dependent (if provided) + * 3. generic (if no BSP and no CPU dependent) + * + */ + +#define CPU_PROVIDES_IDLE_THREAD_BODY TRUE + +/* + * Does the stack grow up (toward higher addresses) or down + * (toward lower addresses)? + * + * If TRUE, then the grows upward. + * If FALSE, then the grows toward smaller addresses. + * + */ + +#define CPU_STACK_GROWS_UP FALSE + +/* + * The following is the variable attribute used to force alignment + * of critical RTEMS structures. On some processors it may make + * sense to have these aligned on tighter boundaries than + * the minimum requirements of the compiler in order to have as + * much of the critical data area as possible in a cache line. + * + * The placement of this macro in the declaration of the variables + * is based on the syntactically requirements of the GNU C + * "__attribute__" extension. For example with GNU C, use + * the following to force a structures to a 32 byte boundary. + * + * __attribute__ ((aligned (32))) + * + * NOTE: Currently only the Priority Bit Map table uses this feature. + * To benefit from using this, the data must be heavily + * used so it will stay in the cache and used frequently enough + * in the executive to justify turning this on. + * + */ + +#define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (64))) + +/* + * Define what is required to specify how the network to host conversion + * routines are handled. + * + * epiphany Specific Information: + * + * This version of RTEMS is designed specifically to run with + * big endian architectures. If you want little endian, you'll + * have to make the appropriate adjustments here and write + * efficient routines for byte swapping. The epiphany architecture + * doesn't do this very well. + */ + +#define CPU_HAS_OWN_HOST_TO_NETWORK_ROUTINES FALSE +#define CPU_BIG_ENDIAN FALSE +#define CPU_LITTLE_ENDIAN TRUE + +/* + * The following defines the number of bits actually used in the + * interrupt field of the task mode. How those bits map to the + * CPU interrupt levels is defined by the routine _CPU_ISR_Set_level(). + * + */ + +#define CPU_MODES_INTERRUPT_MASK 0x00000001 + +/* + * Processor defined structures required for cpukit/score. + */ + +/* + * Contexts + * + * Generally there are 2 types of context to save. + * 1. Interrupt registers to save + * 2. Task level registers to save + * + * This means we have the following 3 context items: + * 1. task level context stuff:: Context_Control + * 2. floating point task stuff:: Context_Control_fp + * 3. special interrupt level context :: Context_Control_interrupt + * + * On some processors, it is cost-effective to save only the callee + * preserved registers during a task context switch. This means + * that the ISR code needs to save those registers which do not + * persist across function calls. It is not mandatory to make this + * distinctions between the caller/callee saves registers for the + * purpose of minimizing context saved during task switch and on interrupts. + * If the cost of saving extra registers is minimal, simplicity is the + * choice. Save the same context on interrupt entry as for tasks in + * this case. + * + * Additionally, if gdb is to be made aware of RTEMS tasks for this CPU, then + * care should be used in designing the context area. + * + * On some CPUs with hardware floating point support, the Context_Control_fp + * structure will not be used or it simply consist of an array of a + * fixed number of bytes. This is done when the floating point context + * is dumped by a "FP save context" type instruction and the format + * is not really defined by the CPU. In this case, there is no need + * to figure out the exact format -- only the size. Of course, although + * this is enough information for RTEMS, it is probably not enough for + * a debugger such as gdb. But that is another problem. + * + * + */ +#ifndef ASM + +typedef struct { + uint32_t r[64]; + + uint32_t status; + uint32_t config; + uint32_t iret; + +#ifdef RTEMS_SMP + /** + * @brief On SMP configurations the thread context must contain a boolean + * indicator to signal if this context is executing on a processor. + * + * This field must be updated during a context switch. The context switch + * to the heir must wait until the heir context indicates that it is no + * longer executing on a processor. The context switch must also check if + * a thread dispatch is necessary to honor updates of the heir thread for + * this processor. This indicator must be updated using an atomic test and + * set operation to ensure that at most one processor uses the heir + * context at the same time. + * + * @code + * void _CPU_Context_switch( + * Context_Control *executing, + * Context_Control *heir + * ) + * { + * save( executing ); + * + * executing->is_executing = false; + * memory_barrier(); + * + * if ( test_and_set( &heir->is_executing ) ) { + * do { + * Per_CPU_Control *cpu_self = _Per_CPU_Get_snapshot(); + * + * if ( cpu_self->dispatch_necessary ) { + * heir = _Thread_Get_heir_and_make_it_executing( cpu_self ); + * } + * } while ( test_and_set( &heir->is_executing ) ); + * } + * + * restore( heir ); + * } + * @endcode + */ + volatile bool is_executing; +#endif +} Context_Control; + +#define _CPU_Context_Get_SP( _context ) \ + (_context)->r[13] + +typedef struct { + /** FPU registers are listed here */ + double some_float_register; +} Context_Control_fp; + +typedef Context_Control CPU_Interrupt_frame; + +/* + * The size of the floating point context area. On some CPUs this + * will not be a "sizeof" because the format of the floating point + * area is not defined -- only the size is. This is usually on + * CPUs with a "floating point save context" instruction. + * + * epiphany Specific Information: + * + */ + +#define CPU_CONTEXT_FP_SIZE 0 +SCORE_EXTERN Context_Control_fp _CPU_Null_fp_context; + +/* + * Amount of extra stack (above minimum stack size) required by + * MPCI receive server thread. Remember that in a multiprocessor + * system this thread must exist and be able to process all directives. + * + */ + +#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0 + +/* + * Should be large enough to run all RTEMS tests. This insures + * that a "reasonable" small application should not have any problems. + * + */ + +#define CPU_STACK_MINIMUM_SIZE 4096 + +/* + * CPU's worst alignment requirement for data types on a byte boundary. This + * alignment does not take into account the requirements for the stack. + * + */ + +#define CPU_ALIGNMENT 8 + +/* + * This is defined if the port has a special way to report the ISR nesting + * level. Most ports maintain the variable _ISR_Nest_level. + */ +#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE + +/* + * This number corresponds to the byte alignment requirement for the + * heap handler. This alignment requirement may be stricter than that + * for the data types alignment specified by CPU_ALIGNMENT. It is + * common for the heap to follow the same alignment requirement as + * CPU_ALIGNMENT. If the CPU_ALIGNMENT is strict enough for the heap, + * then this should be set to CPU_ALIGNMENT. + * + * NOTE: This does not have to be a power of 2 although it should be + * a multiple of 2 greater than or equal to 2. The requirement + * to be a multiple of 2 is because the heap uses the least + * significant field of the front and back flags to indicate + * that a block is in use or free. So you do not want any odd + * length blocks really putting length data in that bit. + * + * On byte oriented architectures, CPU_HEAP_ALIGNMENT normally will + * have to be greater or equal to than CPU_ALIGNMENT to ensure that + * elements allocated from the heap meet all restrictions. + * + */ + +#define CPU_HEAP_ALIGNMENT CPU_ALIGNMENT + +/* + * This number corresponds to the byte alignment requirement for memory + * buffers allocated by the partition manager. This alignment requirement + * may be stricter than that for the data types alignment specified by + * CPU_ALIGNMENT. It is common for the partition to follow the same + * alignment requirement as CPU_ALIGNMENT. If the CPU_ALIGNMENT is strict + * enough for the partition, then this should be set to CPU_ALIGNMENT. + * + * NOTE: This does not have to be a power of 2. It does have to + * be greater or equal to than CPU_ALIGNMENT. + * + */ + +#define CPU_PARTITION_ALIGNMENT CPU_ALIGNMENT + +/* + * This number corresponds to the byte alignment requirement for the + * stack. This alignment requirement may be stricter than that for the + * data types alignment specified by CPU_ALIGNMENT. If the CPU_ALIGNMENT + * is strict enough for the stack, then this should be set to 0. + * + * NOTE: This must be a power of 2 either 0 or greater than CPU_ALIGNMENT. + * + */ + +#define CPU_STACK_ALIGNMENT 8 + +/* ISR handler macros */ + +/* + * Support routine to initialize the RTEMS vector table after it is allocated. + * + * NO_CPU Specific Information: + * + * XXX document implementation including references if appropriate + */ + +#define _CPU_Initialize_vectors() + +/* + * Disable all interrupts for an RTEMS critical section. The previous + * level is returned in _level. + * + */ + +static inline uint32_t epiphany_interrupt_disable( void ) +{ + uint32_t sr; + __asm__ __volatile__ ("movfs %[sr], status \n" : [sr] "=r" (sr):); + __asm__ __volatile__("gid \n"); + return sr; +} + +static inline void epiphany_interrupt_enable(uint32_t level) +{ + __asm__ __volatile__("gie \n"); + __asm__ __volatile__ ("movts status, %[level] \n" :: [level] "r" (level):); +} + +#define _CPU_ISR_Disable( _level ) \ + _level = epiphany_interrupt_disable() + +/* + * Enable interrupts to the previous level (returned by _CPU_ISR_Disable). + * This indicates the end of an RTEMS critical section. The parameter + * _level is not modified. + * + */ + +#define _CPU_ISR_Enable( _level ) \ + epiphany_interrupt_enable( _level ) + +/* + * This temporarily restores the interrupt to _level before immediately + * disabling them again. This is used to divide long RTEMS critical + * sections into two or more parts. The parameter _level is not + * modified. + * + */ + +#define _CPU_ISR_Flash( _level ) \ + do{ \ + if ( (_level & 0x2) != 0 ) \ + _CPU_ISR_Enable( _level ); \ + epiphany_interrupt_disable(); \ + } while(0) + +/* + * Map interrupt level in task mode onto the hardware that the CPU + * actually provides. Currently, interrupt levels which do not + * map onto the CPU in a generic fashion are undefined. Someday, + * it would be nice if these were "mapped" by the application + * via a callout. For example, m68k has 8 levels 0 - 7, levels + * 8 - 255 would be available for bsp/application specific meaning. + * This could be used to manage a programmable interrupt controller + * via the rtems_task_mode directive. + * + * The get routine usually must be implemented as a subroutine. + * + */ + +void _CPU_ISR_Set_level( uint32_t level ); + +uint32_t _CPU_ISR_Get_level( void ); + +/* end of ISR handler macros */ + +/* Context handler macros */ + +/* + * Initialize the context to a state suitable for starting a + * task after a context restore operation. Generally, this + * involves: + * + * - setting a starting address + * - preparing the stack + * - preparing the stack and frame pointers + * - setting the proper interrupt level in the context + * - initializing the floating point context + * + * This routine generally does not set any unnecessary register + * in the context. The state of the "general data" registers is + * undefined at task start time. + * + * NOTE: This is_fp parameter is TRUE if the thread is to be a floating + * point thread. This is typically only used on CPUs where the + * FPU may be easily disabled by software such as on the SPARC + * where the PSR contains an enable FPU bit. + * + */ + +/** + * @brief Account for GCC red-zone + * + * The following macro is used when initializing task's stack + * to account for GCC red-zone. + */ + +#define EPIPHANY_GCC_RED_ZONE_SIZE 128 + +/** + * @brief Initializes the CPU context. + * + * The following steps are performed: + * - setting a starting address + * - preparing the stack + * - preparing the stack and frame pointers + * - setting the proper interrupt level in the context + * + * @param[in] context points to the context area + * @param[in] stack_area_begin is the low address of the allocated stack area + * @param[in] stack_area_size is the size of the stack area in bytes + * @param[in] new_level is the interrupt level for the task + * @param[in] entry_point is the task's entry point + * @param[in] is_fp is set to @c true if the task is a floating point task + * @param[in] tls_area is the thread-local storage (TLS) area + */ +void _CPU_Context_Initialize( + Context_Control *context, + void *stack_area_begin, + size_t stack_area_size, + uint32_t new_level, + void (*entry_point)( void ), + bool is_fp, + void *tls_area +); + +/* + * This routine is responsible for somehow restarting the currently + * executing task. If you are lucky, then all that is necessary + * is restoring the context. Otherwise, there will need to be + * a special assembly routine which does something special in this + * case. Context_Restore should work most of the time. It will + * not work if restarting self conflicts with the stack frame + * assumptions of restoring a context. + * + */ + +#define _CPU_Context_Restart_self( _the_context ) \ + _CPU_Context_restore( (_the_context) ) + +/* + * The purpose of this macro is to allow the initial pointer into + * a floating point context area (used to save the floating point + * context) to be at an arbitrary place in the floating point + * context area. + * + * This is necessary because some FP units are designed to have + * their context saved as a stack which grows into lower addresses. + * Other FP units can be saved by simply moving registers into offsets + * from the base of the context area. Finally some FP units provide + * a "dump context" instruction which could fill in from high to low + * or low to high based on the whim of the CPU designers. + * + */ + +#define _CPU_Context_Fp_start( _base, _offset ) \ + ( (void *) _Addresses_Add_offset( (_base), (_offset) ) ) + +/* + * This routine initializes the FP context area passed to it to. + * There are a few standard ways in which to initialize the + * floating point context. The code included for this macro assumes + * that this is a CPU in which a "initial" FP context was saved into + * _CPU_Null_fp_context and it simply copies it to the destination + * context passed to it. + * + * Other models include (1) not doing anything, and (2) putting + * a "null FP status word" in the correct place in the FP context. + * + */ + +#define _CPU_Context_Initialize_fp( _destination ) \ + { \ + *(*(_destination)) = _CPU_Null_fp_context; \ + } + +/* end of Context handler macros */ + +/* Fatal Error manager macros */ + +/* + * This routine copies _error into a known place -- typically a stack + * location or a register, optionally disables interrupts, and + * halts/stops the CPU. + * + */ + +#define _CPU_Fatal_halt(_source, _error ) \ + printk("Fatal Error %d.%d Halted\n",_source, _error); \ + asm("trap 3" :: "r" (_error)); \ + for(;;) + +/* end of Fatal Error manager macros */ + +/* Bitfield handler macros */ + +/* + * This routine sets _output to the bit number of the first bit + * set in _value. _value is of CPU dependent type Priority_Bit_map_control. + * This type may be either 16 or 32 bits wide although only the 16 + * least significant bits will be used. + * + * There are a number of variables in using a "find first bit" type + * instruction. + * + * (1) What happens when run on a value of zero? + * (2) Bits may be numbered from MSB to LSB or vice-versa. + * (3) The numbering may be zero or one based. + * (4) The "find first bit" instruction may search from MSB or LSB. + * + * RTEMS guarantees that (1) will never happen so it is not a concern. + * (2),(3), (4) are handled by the macros _CPU_Priority_mask() and + * _CPU_Priority_bits_index(). These three form a set of routines + * which must logically operate together. Bits in the _value are + * set and cleared based on masks built by _CPU_Priority_mask(). + * The basic major and minor values calculated by _Priority_Major() + * and _Priority_Minor() are "massaged" by _CPU_Priority_bits_index() + * to properly range between the values returned by the "find first bit" + * instruction. This makes it possible for _Priority_Get_highest() to + * calculate the major and directly index into the minor table. + * This mapping is necessary to ensure that 0 (a high priority major/minor) + * is the first bit found. + * + * This entire "find first bit" and mapping process depends heavily + * on the manner in which a priority is broken into a major and minor + * components with the major being the 4 MSB of a priority and minor + * the 4 LSB. Thus (0 << 4) + 0 corresponds to priority 0 -- the highest + * priority. And (15 << 4) + 14 corresponds to priority 254 -- the next + * to the lowest priority. + * + * If your CPU does not have a "find first bit" instruction, then + * there are ways to make do without it. Here are a handful of ways + * to implement this in software: + * + * - a series of 16 bit test instructions + * - a "binary search using if's" + * - _number = 0 + * if _value > 0x00ff + * _value >>=8 + * _number = 8; + * + * if _value > 0x0000f + * _value >=8 + * _number += 4 + * + * _number += bit_set_table[ _value ] + * + * where bit_set_table[ 16 ] has values which indicate the first + * bit set + * + */ + + /* #define CPU_USE_GENERIC_BITFIELD_CODE FALSE */ +#define CPU_USE_GENERIC_BITFIELD_CODE TRUE +#define CPU_USE_GENERIC_BITFIELD_DATA TRUE + +#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE) + +#define _CPU_Bitfield_Find_first_bit( _value, _output ) \ + { \ + (_output) = 0; /* do something to prevent warnings */ \ + } +#endif + +/* end of Bitfield handler macros */ + +/* + * This routine builds the mask which corresponds to the bit fields + * as searched by _CPU_Bitfield_Find_first_bit(). See the discussion + * for that routine. + * + */ + +#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE) + +#define _CPU_Priority_Mask( _bit_number ) \ + (1 << _bit_number) + +#endif + +/* + * This routine translates the bit numbers returned by + * _CPU_Bitfield_Find_first_bit() into something suitable for use as + * a major or minor component of a priority. See the discussion + * for that routine. + * + */ + +#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE) + +#define _CPU_Priority_bits_index( _priority ) \ + (_priority) + +#endif + +#define CPU_TIMESTAMP_USE_STRUCT_TIMESPEC FALSE +#define CPU_TIMESTAMP_USE_INT64 TRUE +#define CPU_TIMESTAMP_USE_INT64_INLINE FALSE + +typedef struct { +/* There is no CPU specific per-CPU state */ +} CPU_Per_CPU_control; +#endif /* ASM */ + +/** + * Size of a pointer. + * + * This must be an integer literal that can be used by the assembler. This + * value will be used to calculate offsets of structure members. These + * offsets will be used in assembler code. + */ +#define CPU_SIZEOF_POINTER 4 +#define CPU_EXCEPTION_FRAME_SIZE 260 +#define CPU_PER_CPU_CONTROL_SIZE 0 + +#ifndef ASM +typedef uint16_t Priority_bit_map_Word; + +typedef struct { + uint32_t r[62]; + uint32_t status; + uint32_t config; + uint32_t iret; +} CPU_Exception_frame; + +/** + * @brief Prints the exception frame via printk(). + * + * @see rtems_fatal() and RTEMS_FATAL_SOURCE_EXCEPTION. + */ +void _CPU_Exception_frame_print( const CPU_Exception_frame *frame ); + + +/* end of Priority handler macros */ + +/* functions */ + +/* + * _CPU_Initialize + * + * This routine performs CPU dependent initialization. + * + */ + +void _CPU_Initialize( + void +); + +/* + * _CPU_ISR_install_raw_handler + * + * This routine installs a "raw" interrupt handler directly into the + * processor's vector table. + * + */ + +void _CPU_ISR_install_raw_handler( + uint32_t vector, + proc_ptr new_handler, + proc_ptr *old_handler +); + +/* + * _CPU_ISR_install_vector + * + * This routine installs an interrupt vector. + * + * NO_CPU Specific Information: + * + * XXX document implementation including references if appropriate + */ + +void _CPU_ISR_install_vector( + uint32_t vector, + proc_ptr new_handler, + proc_ptr *old_handler +); + +/* + * _CPU_Install_interrupt_stack + * + * This routine installs the hardware interrupt stack pointer. + * + * NOTE: It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STACK + * is TRUE. + * + */ + +void _CPU_Install_interrupt_stack( void ); + +/* + * _CPU_Thread_Idle_body + * + * This routine is the CPU dependent IDLE thread body. + * + * NOTE: It need only be provided if CPU_PROVIDES_IDLE_THREAD_BODY + * is TRUE. + * + */ + +void *_CPU_Thread_Idle_body( uintptr_t ignored ); + +/* + * _CPU_Context_switch + * + * This routine switches from the run context to the heir context. + * + * epiphany Specific Information: + * + * Please see the comments in the .c file for a description of how + * this function works. There are several things to be aware of. + */ + +void _CPU_Context_switch( + Context_Control *run, + Context_Control *heir +); + +/* + * _CPU_Context_restore + * + * This routine is generally used only to restart self in an + * efficient manner. It may simply be a label in _CPU_Context_switch. + * + * NOTE: May be unnecessary to reload some registers. + * + */ + +void _CPU_Context_restore( + Context_Control *new_context +) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE; + +/* + * _CPU_Context_save_fp + * + * This routine saves the floating point context passed to it. + * + */ + +void _CPU_Context_save_fp( + void **fp_context_ptr +); + +/* + * _CPU_Context_restore_fp + * + * This routine restores the floating point context passed to it. + * + */ + +void _CPU_Context_restore_fp( + void **fp_context_ptr +); + +/* The following routine swaps the endian format of an unsigned int. + * It must be static because it is referenced indirectly. + * + * This version will work on any processor, but if there is a better + * way for your CPU PLEASE use it. The most common way to do this is to: + * + * swap least significant two bytes with 16-bit rotate + * swap upper and lower 16-bits + * swap most significant two bytes with 16-bit rotate + * + * Some CPUs have special instructions which swap a 32-bit quantity in + * a single instruction (e.g. i486). It is probably best to avoid + * an "endian swapping control bit" in the CPU. One good reason is + * that interrupts would probably have to be disabled to insure that + * an interrupt does not try to access the same "chunk" with the wrong + * endian. Another good reason is that on some CPUs, the endian bit + * endianness for ALL fetches -- both code and data -- so the code + * will be fetched incorrectly. + * + */ + +static inline unsigned int CPU_swap_u32( + unsigned int value +) +{ + uint32_t byte1, byte2, byte3, byte4, swapped; + + byte4 = (value >> 24) & 0xff; + byte3 = (value >> 16) & 0xff; + byte2 = (value >> 8) & 0xff; + byte1 = value & 0xff; + + swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; + return( swapped ); +} + +#define CPU_swap_u16( value ) \ + (((value&0xff) << 8) | ((value >> 8)&0xff)) + +static inline void _CPU_Context_volatile_clobber( uintptr_t pattern ) +{ + /* TODO */ +} + +static inline void _CPU_Context_validate( uintptr_t pattern ) +{ + while (1) { + /* TODO */ + } +} + +typedef uint32_t CPU_Counter_ticks; + +CPU_Counter_ticks _CPU_Counter_read( void ); + +static inline CPU_Counter_ticks _CPU_Counter_difference( + CPU_Counter_ticks second, + CPU_Counter_ticks first +) +{ + return second - first; +} + +#ifdef RTEMS_SMP + /** + * @brief Performs CPU specific SMP initialization in the context of the boot + * processor. + * + * This function is invoked on the boot processor during system + * initialization. All interrupt stacks are allocated at this point in case + * the CPU port allocates the interrupt stacks. This function is called + * before _CPU_SMP_Start_processor() or _CPU_SMP_Finalize_initialization() is + * used. + * + * @return The count of physically or virtually available processors. + * Depending on the configuration the application may use not all processors. + */ + uint32_t _CPU_SMP_Initialize( void ); + + /** + * @brief Starts a processor specified by its index. + * + * This function is invoked on the boot processor during system + * initialization. + * + * This function will be called after _CPU_SMP_Initialize(). + * + * @param[in] cpu_index The processor index. + * + * @retval true Successful operation. + * @retval false Unable to start this processor. + */ + bool _CPU_SMP_Start_processor( uint32_t cpu_index ); + + /** + * @brief Performs final steps of CPU specific SMP initialization in the + * context of the boot processor. + * + * This function is invoked on the boot processor during system + * initialization. + * + * This function will be called after all processors requested by the + * application have been started. + * + * @param[in] cpu_count The minimum value of the count of processors + * requested by the application configuration and the count of physically or + * virtually available processors. + */ + void _CPU_SMP_Finalize_initialization( uint32_t cpu_count ); + + /** + * @brief Returns the index of the current processor. + * + * An architecture specific method must be used to obtain the index of the + * current processor in the system. The set of processor indices is the + * range of integers starting with zero up to the processor count minus one. + */ + uint32_t _CPU_SMP_Get_current_processor( void ); + + /** + * @brief Sends an inter-processor interrupt to the specified target + * processor. + * + * This operation is undefined for target processor indices out of range. + * + * @param[in] target_processor_index The target processor index. + */ + void _CPU_SMP_Send_interrupt( uint32_t target_processor_index ); + + /** + * @brief Broadcasts a processor event. + * + * Some architectures provide a low-level synchronization primitive for + * processors in a multi-processor environment. Processors waiting for this + * event may go into a low-power state and stop generating system bus + * transactions. This function must ensure that preceding store operations + * can be observed by other processors. + * + * @see _CPU_SMP_Processor_event_receive(). + */ + void _CPU_SMP_Processor_event_broadcast( void ); + + /** + * @brief Receives a processor event. + * + * This function will wait for the processor event and may wait forever if no + * such event arrives. + * + * @see _CPU_SMP_Processor_event_broadcast(). + */ + static inline void _CPU_SMP_Processor_event_receive( void ) + { + __asm__ volatile ( "" : : : "memory" ); + } + + /** + * @brief Gets the is executing indicator of the thread context. + * + * @param[in] context The context. + */ + static inline bool _CPU_Context_Get_is_executing( + const Context_Control *context + ) + { + return context->is_executing; + } + + /** + * @brief Sets the is executing indicator of the thread context. + * + * @param[in] context The context. + * @param[in] is_executing The new value for the is executing indicator. + */ + static inline void _CPU_Context_Set_is_executing( + Context_Control *context, + bool is_executing + ) + { + context->is_executing = is_executing; + } +#endif /* RTEMS_SMP */ + +#endif /* ASM */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/score/cpu/epiphany/rtems/score/cpu_asm.h b/cpukit/score/cpu/epiphany/rtems/score/cpu_asm.h new file mode 100644 index 0000000000..cc091fa909 --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/score/cpu_asm.h @@ -0,0 +1,74 @@ +/** + * @file + * + * @brief Epiphany Assembly File + * + * Very loose template for an include file for the cpu_asm.? file + * if it is implemented as a ".S" file (preprocessed by cpp) instead + * of a ".s" file (preprocessed by gm4 or gasp). + */ + +/* + * 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. + * + */ + +#ifndef _RTEMS_SCORE_CPU_ASM_H +#define _RTEMS_SCORE_CPU_ASM_H + +/* pull in the generated offsets */ + +/* +#include +*/ + +/* + * Hardware General Registers + */ + +/* put something here */ + +/* + * Hardware Floating Point Registers + */ + +/* put something here */ + +/* + * Hardware Control Registers + */ + +/* put something here */ + +/* + * Calling Convention + */ + +/* put something here */ + +/* + * Temporary registers + */ + +/* put something here */ + +/* + * Floating Point Registers - SW Conventions + */ + +/* put something here */ + +/* + * Temporary floating point registers + */ + +/* put something here */ + +#endif + +/* end of file */ diff --git a/cpukit/score/cpu/epiphany/rtems/score/cpuatomic.h b/cpukit/score/cpu/epiphany/rtems/score/cpuatomic.h new file mode 100644 index 0000000000..598ee76b20 --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/score/cpuatomic.h @@ -0,0 +1,14 @@ +/* + * COPYRIGHT (c) 2012-2013 Deng Hengyi. + * + * 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. + */ + +#ifndef _RTEMS_SCORE_ATOMIC_CPU_H +#define _RTEMS_SCORE_ATOMIC_CPU_H + +#include + +#endif /* _RTEMS_SCORE_ATOMIC_CPU_H */ diff --git a/cpukit/score/cpu/epiphany/rtems/score/epiphany-utility.h b/cpukit/score/cpu/epiphany/rtems/score/epiphany-utility.h new file mode 100644 index 0000000000..bf223f93bf --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/score/epiphany-utility.h @@ -0,0 +1,180 @@ +/** + * @file + * + * @ingroup ScoreCPU + * + * @brief This include file contains macros pertaining to the + * Epiphany processor family. + */ + +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _EPIPHANY_UTILITY_H +#define _EPIPHANY_UTILITY_H + +/* eCore IRQs */ +typedef enum +{ + START, + SW_EXCEPTION, + MEM_FAULT, + TIMER0, + TIMER1, + SMP_MESSAGE, + DMA0, + DMA1, + SER, +} EPIPHANY_IRQ_PER_CORE_T; + +/* Per-core IO mapped register addresses + * @see Epiphany architecture reference. + */ +#define EPIPHANY_PER_CORE_REG_CONFIG 0xF0400 +#define EPIPHANY_PER_CORE_REG_STATUS 0xF0404 +#define EPIPHANY_PER_CORE_REG_PC 0xF0408 +#define EPIPHANY_PER_CORE_REG_DEBUGSTATUS 0xF040C +#define EPIPHANY_PER_CORE_REG_LC 0xF0414 +#define EPIPHANY_PER_CORE_REG_LS 0xF0418 +#define EPIPHANY_PER_CORE_REG_LE 0xF041C +#define EPIPHANY_PER_CORE_REG_IRET 0xF0420 +#define EPIPHANY_PER_CORE_REG_IMASK 0xF0424 +#define EPIPHANY_PER_CORE_REG_ILAT 0xF0428 +#define EPIPHANY_PER_CORE_REG_ILATST 0xF042C +#define EPIPHANY_PER_CORE_REG_ILATCL 0xF0430 +#define EPIPHANY_PER_CORE_REG_IPEND 0xF0434 +#define EPIPHANY_PER_CORE_REG_FSTATUS 0xF0440 +#define EPIPHANY_PER_CORE_REG_DEBUGCMD 0xF0448 +#define EPIPHANY_PER_CORE_REG_RESETCORE 0xF070C + +/* Event timer registers */ +#define EPIPHANY_PER_CORE_REG_CTIMER0 0xF0438 +#define EPIPHANY_PER_CORE_REG_CTIMER1 0xF043C + +/* Processor control registers */ +#define EPIPHANY_PER_CORE_REG_MEMSTATUS 0xF0604 +#define EPIPHANY_PER_CORE_REG_MEMPROTECT 0xF0608 + +/* DMA Registers */ +#define EPIPHANY_PER_CORE_REG_DMA0CONFIG 0xF0500 +#define EPIPHANY_PER_CORE_REG_DMA0STRIDE 0xF0504 +#define EPIPHANY_PER_CORE_REG_DMA0COUNT 0xF0508 +#define EPIPHANY_PER_CORE_REG_DMA0SRCADDR 0xF050C +#define EPIPHANY_PER_CORE_REG_DMA0DSTADDR 0xF0510 +#define EPIPHANY_PER_CORE_REG_DMA0AUTO0 0xF0514 +#define EPIPHANY_PER_CORE_REG_DMA0AUTO1 0xF0518 +#define EPIPHANY_PER_CORE_REG_DMA0STATUS 0xF051C +#define EPIPHANY_PER_CORE_REG_DMA1CONFIG 0xF0520 +#define EPIPHANY_PER_CORE_REG_DMA1STRIDE 0xF0524 +#define EPIPHANY_PER_CORE_REG_DMA1COUNT 0xF0528 +#define EPIPHANY_PER_CORE_REG_DMA1SRCADDR 0xF052C +#define EPIPHANY_PER_CORE_REG_DMA1DSTADDR 0xF0530 +#define EPIPHANY_PER_CORE_REG_DMA1AUTO0 0xF0534 +#define EPIPHANY_PER_CORE_REG_DMA1AUTO1 0xF0538 +#define EPIPHANY_PER_CORE_REG_DMA1STATUS 0xF053C + +/* Mesh Node Control Registers */ +#define EPIPHANY_PER_CORE_REG_MESHCONFIG 0xF0700 +#define EPIPHANY_PER_CORE_REG_COREID 0xF0704 +#define EPIPHANY_PER_CORE_REG_MULTICAST 0xF0708 +#define EPIPHANY_PER_CORE_REG_CMESHROUTE 0xF0710 +#define EPIPHANY_PER_CORE_REG_XMESHROUTE 0xF0714 +#define EPIPHANY_PER_CORE_REG_RMESHROUTE 0xF0718 + +/* This macros constructs an address space of epiphany cores + * from their IDs. + */ +#define EPIPHANY_COREID_TO_MSB_ADDR(id) (id) << 20 + +/* Construct a complete/absolute IO mapped address register from + * core ID and register name + */ +#define EPIPHANY_GET_REG_ABSOLUTE_ADDR(coreid, reg) \ + (EPIPHANY_COREID_TO_MSB_ADDR(coreid) | (reg)) + +#define EPIPHANY_REG(reg) (uint32_t *) (reg) + +/* Read register with its absolute address */ +static inline uint32_t read_epiphany_reg(volatile uint32_t reg_addr) +{ + return *(EPIPHANY_REG(reg_addr)); +} + +/* Write register with its abolute address */ +static inline void write_epiphany_reg(volatile uint32_t reg_addr, uint32_t val) +{ + *(EPIPHANY_REG(reg_addr)) = val; +} + +/* Epiphany uses 12 bits for defining core IDs, while RTEMS uses + * linear IDs. The following function converts RTEMS linear IDs to + * Epiphany corresponding ones + */ +static const uint32_t map[16] = +{ + 0x808, 0x809, 0x80A, 0x80B, + 0x848, 0x849, 0x84A, 0x84B, + 0x888, 0x889, 0x88A, 0x88B, + 0x8C8, 0x8C9, 0x8CA, 0x8CB +}; + +static inline uint32_t rtems_coreid_to_epiphany_map(uint32_t rtems_id) +{ + return map[rtems_id]; +} + +/* Epiphany uses 12 bits for defining core IDs, while RTEMS uses + * linear IDs. The following function is used to map Epiphany IDs to + * RTEMS linear IDs. + */ +static inline uint32_t epiphany_coreid_to_rtems_map(uint32_t epiphany_id) +{ + register uint32_t coreid asm ("r17") = epiphany_id; + + /* Mapping from Epiphany IDs to 0-16 IDs macro */ + __asm__ __volatile__(" \ + movfs r17, coreid \ + mov r19, #0x003 \ + mov r20, #0x0F0 \ + and r19, r17, r19 \ + and r20, r17, r20 \ + lsr r20, r20, #4 \ + add r17, r19, r20 \ + "); + + /* coreid or r17 now holds the rtems core id */ + return coreid; +} + +static inline uint32_t _Epiphany_Get_current_processor() +{ + uint32_t coreid; + + asm volatile ("movfs %0, coreid" : "=r" (coreid): ); + + return epiphany_coreid_to_rtems_map(coreid); +} +#endif /* _EPIPHANY_UTILITY_H */ diff --git a/cpukit/score/cpu/epiphany/rtems/score/epiphany.h b/cpukit/score/cpu/epiphany/rtems/score/epiphany.h new file mode 100644 index 0000000000..60d975581f --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/score/epiphany.h @@ -0,0 +1,64 @@ +/** + * @file rtems/score/epiphany.h + */ + +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-1999, 2010. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RTEMS_SCORE_EPIPHANY_H +#define _RTEMS_SCORE_EPIPHANY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains the information required to build + * RTEMS for a particular member of the Epiphany family. + * It does this by setting variables to indicate which + * implementation dependent features are present in a particular + * member of the family. + * + * This is a good place to list all the known CPU models + * that this port supports and which RTEMS CPU model they correspond + * to. + */ + + /* + * Define the name of the CPU family and specific model. + */ + +#define CPU_NAME "EPIPHANY" +#define CPU_MODEL_NAME "EPIPHANY" + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_SCORE_EPIPHANY_H */ diff --git a/cpukit/score/cpu/epiphany/rtems/score/types.h b/cpukit/score/cpu/epiphany/rtems/score/types.h new file mode 100644 index 0000000000..5b6c503739 --- /dev/null +++ b/cpukit/score/cpu/epiphany/rtems/score/types.h @@ -0,0 +1,68 @@ +/** + * @file + * + * @brief Epiphany Architecture Types API + */ + +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + #ifndef _RTEMS_SCORE_TYPES_H +#define _RTEMS_SCORE_TYPES_H + +#include + +#ifndef ASM + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup ScoreCPU + */ +/**@{**/ + +/* + * This section defines the basic types for this processor. + */ + +/** Type that can store a 32-bit integer or a pointer. */ +typedef uintptr_t CPU_Uint32ptr; + +typedef uint16_t Priority_bit_map_Word; +typedef void epiphany_isr; +typedef void ( *epiphany_isr_entry )( void ); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !ASM */ + +#endif -- cgit v1.2.3 From 6f71dcb7cdaff53d8b44ea7c13ddb48d274663e7 Mon Sep 17 00:00:00 2001 From: Hesham ALMatary Date: Thu, 21 May 2015 17:53:53 +0100 Subject: Epiphany: Add the first epiphany_sim BSP v4 This BSP in intended to run on the simulator that should be built from RSB. When building RTEMS for Epiphany --disable-networking must be provided part of the configure command. --- c/src/aclocal/rtems-cpu-subdirs.m4 | 1 + c/src/lib/libbsp/epiphany/Makefile.am | 8 + c/src/lib/libbsp/epiphany/acinclude.m4 | 10 + c/src/lib/libbsp/epiphany/configure.ac | 19 ++ c/src/lib/libbsp/epiphany/epiphany_sim/Makefile.am | 95 ++++++ c/src/lib/libbsp/epiphany/epiphany_sim/README | 6 + c/src/lib/libbsp/epiphany/epiphany_sim/bsp_specs | 13 + .../lib/libbsp/epiphany/epiphany_sim/configure.ac | 36 ++ .../epiphany/epiphany_sim/console/console-io.c | 104 ++++++ .../lib/libbsp/epiphany/epiphany_sim/include/bsp.h | 55 +++ .../libbsp/epiphany/epiphany_sim/include/bspopts.h | 68 ++++ .../lib/libbsp/epiphany/epiphany_sim/include/irq.h | 49 +++ .../libbsp/epiphany/epiphany_sim/include/tm27.h | 53 +++ c/src/lib/libbsp/epiphany/epiphany_sim/irq/irq.c | 62 ++++ .../epiphany_sim/make/custom/epiphany_sim.cfg | 7 + .../lib/libbsp/epiphany/epiphany_sim/preinstall.am | 104 ++++++ .../lib/libbsp/epiphany/epiphany_sim/start/start.S | 167 ++++++++++ .../libbsp/epiphany/epiphany_sim/startup/linkcmds | 369 +++++++++++++++++++++ .../lib/libbsp/epiphany/epiphany_sim/timer/timer.c | 109 ++++++ c/src/lib/libbsp/epiphany/preinstall.am | 7 + .../epiphany/shared/include/linker-symbols.h | 81 +++++ 21 files changed, 1423 insertions(+) create mode 100644 c/src/lib/libbsp/epiphany/Makefile.am create mode 100644 c/src/lib/libbsp/epiphany/acinclude.m4 create mode 100644 c/src/lib/libbsp/epiphany/configure.ac create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/Makefile.am create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/README create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/bsp_specs create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/configure.ac create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/console/console-io.c create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/include/bsp.h create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/include/bspopts.h create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/include/irq.h create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/include/tm27.h create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/irq/irq.c create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/make/custom/epiphany_sim.cfg create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/preinstall.am create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/start/start.S create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/startup/linkcmds create mode 100644 c/src/lib/libbsp/epiphany/epiphany_sim/timer/timer.c create mode 100644 c/src/lib/libbsp/epiphany/preinstall.am create mode 100644 c/src/lib/libbsp/epiphany/shared/include/linker-symbols.h diff --git a/c/src/aclocal/rtems-cpu-subdirs.m4 b/c/src/aclocal/rtems-cpu-subdirs.m4 index 9593d34a6c..524edac41e 100644 --- a/c/src/aclocal/rtems-cpu-subdirs.m4 +++ b/c/src/aclocal/rtems-cpu-subdirs.m4 @@ -12,6 +12,7 @@ AC_DEFUN([RTEMS_CPU_SUBDIRS], case $RTEMS_CPU in _RTEMS_CPU_SUBDIR([arm],[$1]);; _RTEMS_CPU_SUBDIR([bfin],[$1]);; +_RTEMS_CPU_SUBDIR([epiphany],[$1]);; _RTEMS_CPU_SUBDIR([avr],[$1]);; _RTEMS_CPU_SUBDIR([h8300],[$1]);; _RTEMS_CPU_SUBDIR([i386],[$1]);; diff --git a/c/src/lib/libbsp/epiphany/Makefile.am b/c/src/lib/libbsp/epiphany/Makefile.am new file mode 100644 index 0000000000..cdcc3fbd5c --- /dev/null +++ b/c/src/lib/libbsp/epiphany/Makefile.am @@ -0,0 +1,8 @@ +ACLOCAL_AMFLAGS = -I ../../../aclocal +## Descend into the @RTEMS_BSP_FAMILY@ directory +## Currently, the shared directory is not explicitly +## added but it is present in the source tree. +SUBDIRS = @RTEMS_BSP_FAMILY@ +include $(srcdir)/preinstall.am +include $(top_srcdir)/../../../automake/subdirs.am +include $(top_srcdir)/../../../automake/local.am diff --git a/c/src/lib/libbsp/epiphany/acinclude.m4 b/c/src/lib/libbsp/epiphany/acinclude.m4 new file mode 100644 index 0000000000..0fe1e2e79d --- /dev/null +++ b/c/src/lib/libbsp/epiphany/acinclude.m4 @@ -0,0 +1,10 @@ +# RTEMS_CHECK_BSPDIR(RTEMS_BSP_FAMILY) +AC_DEFUN([RTEMS_CHECK_BSPDIR], +[ + case "$1" in + epiphany_sim ) + AC_CONFIG_SUBDIRS([epiphany_sim]);; + *) + AC_MSG_ERROR([Invalid BSP]);; + esac +]) diff --git a/c/src/lib/libbsp/epiphany/configure.ac b/c/src/lib/libbsp/epiphany/configure.ac new file mode 100644 index 0000000000..bba5440ca9 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/configure.ac @@ -0,0 +1,19 @@ +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([rtems-c-src-lib-libbsp-epiphany],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla]) +AC_CONFIG_SRCDIR([epiphany_sim]) +RTEMS_TOP(../../../../..) + +RTEMS_CANONICAL_TARGET_CPU +AM_INIT_AUTOMAKE([no-define foreign subdir-objects 1.12.2]) +AM_MAINTAINER_MODE + +RTEMS_ENV_RTEMSBSP +RTEMS_PROJECT_ROOT + +RTEMS_CHECK_BSPDIR([$RTEMS_BSP_FAMILY]) + +# Explicitly list all Makefiles here +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/Makefile.am b/c/src/lib/libbsp/epiphany/epiphany_sim/Makefile.am new file mode 100644 index 0000000000..0b84843b98 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/Makefile.am @@ -0,0 +1,95 @@ +## +# +# @brief Makefile of LibBSP for the Epiphany simulator. +# +# +ACLOCAL_AMFLAGS = -I ../../../../aclocal + +include $(top_srcdir)/../../../../automake/compile.am + +include_bspdir = $(includedir)/bsp +include_libcpudir = $(includedir)/libcpu + +dist_project_lib_DATA = bsp_specs + +############################################################################### +# Header # +############################################################################### + +include_HEADERS = include/bsp.h +include_HEADERS += include/tm27.h +include_HEADERS += ../../shared/include/coverhd.h + +nodist_include_bsp_HEADERS = ../../shared/include/bootcard.h +include_bsp_HEADERS = ../shared/include/linker-symbols.h + +include_bsp_HEADERS += ../../../libbsp/shared/include/mm.h +include_bsp_HEADERS += ../../shared/include/utility.h +include_bsp_HEADERS += ../../shared/include/irq-generic.h +include_bsp_HEADERS += ../../shared/include/irq-info.h +include_bsp_HEADERS += ../../shared/include/stackalloc.h +include_bsp_HEADERS += ../../shared/include/console-polled.h +include_bsp_HEADERS += include/irq.h + +nodist_include_HEADERS = include/bspopts.h + +############################################################################### +# Data # +############################################################################### +noinst_LIBRARIES = libbspstart.a + +libbspstart_a_SOURCES = start/start.S + +project_lib_DATA = start/start.$(OBJEXT) + +project_lib_DATA += startup/linkcmds + +############################################################################### +# LibBSP # +############################################################################### + +noinst_LIBRARIES += libbsp.a + +# Startup +libbsp_a_SOURCES = ../../shared/bspreset.c +libbsp_a_SOURCES += ../../shared/bspstart.c + +# Shared +libbsp_a_SOURCES += ../../shared/bootcard.c +libbsp_a_SOURCES += ../../shared/bspclean.c +libbsp_a_SOURCES += ../../shared/bsplibc.c +libbsp_a_SOURCES += ../../shared/bsppost.c +libbsp_a_SOURCES += ../../shared/bsppredriverhook.c +libbsp_a_SOURCES += ../../shared/bsppretaskinghook.c +libbsp_a_SOURCES += ../../shared/gnatinstallhandler.c +libbsp_a_SOURCES += ../../shared/sbrk.c +libbsp_a_SOURCES += ../../shared/src/stackalloc.c +libbsp_a_SOURCES += ../../shared/bspgetworkarea.c + +# clock +libbsp_a_SOURCES += ../../shared/clock_driver_simidle.c + +# Timer +libbsp_a_SOURCES += timer/timer.c + +# console +libbsp_a_SOURCES += ../../shared/console-polled.c + +# IRQ +libbsp_a_SOURCES += ../../shared/src/irq-default-handler.c +libbsp_a_SOURCES += ../../shared/src/irq-generic.c +libbsp_a_SOURCES += ../../shared/src/irq-info.c +libbsp_a_SOURCES += irq/irq.c + +# Cache +libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c +libbsp_a_SOURCES += ../../shared/include/cache_.h +libbsp_a_CPPFLAGS = -I$(srcdir)/../../shared/include + +# debugio +libbsp_a_SOURCES += console/console-io.c + +DISTCLEANFILES = include/bspopts.h + +include $(srcdir)/preinstall.am +include $(top_srcdir)/../../../../automake/local.am diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/README b/c/src/lib/libbsp/epiphany/epiphany_sim/README new file mode 100644 index 0000000000..7127d91a66 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/README @@ -0,0 +1,6 @@ +This BSP is intended to run on epiphany-*-run simulator. + +From command line type: + +$ epiphany-rtems4.11-run -e=on --memory-region 0x8e000000,0x2000000 \ + $PATH_TO_RTEMS_EXE diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/bsp_specs b/c/src/lib/libbsp/epiphany/epiphany_sim/bsp_specs new file mode 100644 index 0000000000..082653ad22 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/bsp_specs @@ -0,0 +1,13 @@ +%rename endfile old_endfile +%rename startfile old_startfile +%rename link old_link + +*startfile: +%{!qrtems: %(old_startfile)} \ +%{!nostdlib: %{qrtems: start.o%s crti.o%s crtbegin.o%s -e _start}} + +*link: +%{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} + +*endfile: +%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s } diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/configure.ac b/c/src/lib/libbsp/epiphany/epiphany_sim/configure.ac new file mode 100644 index 0000000000..016b135c34 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/configure.ac @@ -0,0 +1,36 @@ +## +# +# @file +# +# @brief Configure script of LibBSP for epiphany_sim BSP. +# + +AC_PREREQ(2.69) +AC_INIT([rtems-c-src-lib-libbsp-epiphany-sim],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla]) +AC_CONFIG_SRCDIR([bsp_specs]) +RTEMS_TOP(../../../../../..) + +RTEMS_CANONICAL_TARGET_CPU +AM_INIT_AUTOMAKE([no-define nostdinc foreign subdir-objects 1.12.2]) +RTEMS_BSP_CONFIGURE + +RTEMS_BSPOPTS_SET([BSP_START_RESET_VECTOR],[*],[]) +RTEMS_BSPOPTS_HELP([BSP_START_RESET_VECTOR],[reset vector address for BSP +start]) + +RTEMS_BSPOPTS_SET([BSP_EPIPHANY_PERIPHCLK],[*],[100000000U]) +RTEMS_BSPOPTS_HELP([BSP_EPIPHANY_PERIPHCLK],[epiphany PERIPHCLK clock +frequency in Hz]) + +RTEMS_PROG_CC_FOR_TARGET([-ansi -fasm]) +RTEMS_CANONICALIZE_TOOLS +RTEMS_PROG_CCAS + +RTEMS_CHECK_SMP +AM_CONDITIONAL(HAS_SMP,[test "$rtems_cv_HAS_SMP" = "yes"]) + +RTEMS_BSP_CLEANUP_OPTIONS(0, 1) +RTEMS_BSP_LINKCMDS + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/console/console-io.c b/c/src/lib/libbsp/epiphany/epiphany_sim/console/console-io.c new file mode 100644 index 0000000000..e3da54389f --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/console/console-io.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +static void outbyte_console( char ); +static char inbyte_console( void ); + +void console_initialize_hardware(void) +{ + /* Do nothing */ +} + +/* Epiphany simulator would handle this system call */ +static void outbyte_console(char c) +{ + register int chan asm("r0") = STDOUT_FILENO; + register void* addr asm("r1") = &c; + register int len asm("r2") = 1; + + /* Invoke write system call to be handled by Epiphany simulator */ + __asm__ __volatile__ ("trap 0" : : "r" (chan), "r" (addr), "r" (len)); +} + +static char inbyte_console(void) +{ + char c; + register int chan asm("r0") = STDIN_FILENO; + register void* addr asm("r1") = &c; + register int len asm("r2") = 1; + + /* Invoke read system call to be handled by Epiphany simulator */ + asm ("trap 1" :: "r" (chan), "r" (addr), "r" (len)); + return c; +} + +/* + * console_outbyte_polled + * + * This routine transmits a character using polling. + */ +void console_outbyte_polled( + int port, + char ch +) +{ + outbyte_console( ch ); +} + +/* + * console_inbyte_nonblocking + * + * This routine polls for a character. + */ + +int console_inbyte_nonblocking(int port) +{ + char c; + + c = inbyte_console(); + if (!c) + return -1; + return (int) c; +} + +/* + * To support printk + */ + +#include + +static void Epiphany_output_char(char c) { console_outbyte_polled( 0, c ); } + +BSP_output_char_function_type BSP_output_char = Epiphany_output_char; +BSP_polling_getchar_function_type BSP_poll_char = + (void *)console_inbyte_nonblocking; diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/include/bsp.h b/c/src/lib/libbsp/epiphany/epiphany_sim/include/bsp.h new file mode 100644 index 0000000000..1eb91ce8d6 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/include/bsp.h @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef LIBBSP_EPIPHANY_EPIPHANY_SIM_H +#define LIBBSP_EPIPHANY_EPIPHANY_SIM_H + +#include +#include +#include + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Constants */ +Thread clock_driver_sim_idle_body(uintptr_t); +#define BSP_IDLE_TASK_BODY clock_driver_sim_idle_body + +#ifdef __cplusplus +} +#endif + +#endif /* LIBBSP_EPIPHANY_PARALLELLA_H */ diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/include/bspopts.h b/c/src/lib/libbsp/epiphany/epiphany_sim/include/bspopts.h new file mode 100644 index 0000000000..47c2f0da7c --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/include/bspopts.h @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* include/bspopts.h.in. Generated from configure.ac by autoheader. */ + +/* If defined, then the BSP Framework will put a non-zero pattern into the + RTEMS Workspace and C program heap. This should assist in finding code that + assumes memory starts set to zero. */ +#undef BSP_DIRTY_MEMORY + +/* If defined, print a message and wait until pressed before resetting board + when application exits. */ +#undef BSP_PRESS_KEY_FOR_RESET + +/* If defined, prints the exception context when an unexpected exception + occurs. */ +#undef BSP_PRINT_EXCEPTION_CONTEXT + +/* If defined, reset the board when the application exits. */ +#undef BSP_RESET_BOARD_AT_EXIT + +/* reset vector address for BSP start */ +#undef BSP_START_RESET_VECTOR + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/include/irq.h b/c/src/lib/libbsp/epiphany/epiphany_sim/include/irq.h new file mode 100644 index 0000000000..2b15a4536c --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/include/irq.h @@ -0,0 +1,49 @@ +/** + * @file + * + * @ingroup Epiphany_IRQ + * + * @brief Interrupt definitions. + */ + +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef LIBBSP_GENERIC_EPIPHANY_IRQ_H +#define LIBBSP_GENERIC_EPIPHANY_IRQ_H + +#ifndef ASM + +#include +#include +#include + +#define BSP_INTERRUPT_VECTOR_MIN 0x0 +#define BSP_INTERRUPT_VECTOR_MAX 0x24 + +#endif /* ASM */ +#endif /* LIBBSP_GENERIC_OR1K_IRQ_H */ diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/include/tm27.h b/c/src/lib/libbsp/epiphany/epiphany_sim/include/tm27.h new file mode 100644 index 0000000000..10dac820f1 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/include/tm27.h @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RTEMS_TMTEST27 +#error "This is an RTEMS internal file you must not include directly." +#endif + +#ifndef __tm27_h +#define __tm27_h + +/** + * @name Interrupt mechanisms for Time Test 27 + * @{ + */ + +#define MUST_WAIT_FOR_INTERRUPT 0 + +#define Install_tm27_vector( handler ) /* empty */ + +#define Cause_tm27_intr() /* empty */ + +#define Clear_tm27_intr() /* empty */ + +#define Lower_tm27_intr() /* empty */ + +#endif diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/irq/irq.c b/c/src/lib/libbsp/epiphany/epiphany_sim/irq/irq.c new file mode 100644 index 0000000000..323aa0792f --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/irq/irq.c @@ -0,0 +1,62 @@ +/** + * @file + * + * @ingroup epiphany_interrupt + * + * @brief Interrupt support. + */ + +/* + * Epiphany CPU Dependent Source + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* Almost all of the jobs that the following functions should + * do are implemented in cpukit + */ + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %u\n", vector); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + return 0; +} + +rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + return 0; +} + +rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + return 0; +} diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/make/custom/epiphany_sim.cfg b/c/src/lib/libbsp/epiphany/epiphany_sim/make/custom/epiphany_sim.cfg new file mode 100644 index 0000000000..9eea2a04c7 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/make/custom/epiphany_sim.cfg @@ -0,0 +1,7 @@ +include $(RTEMS_ROOT)/make/custom/default.cfg + +RTEMS_CPU = epiphany + +CPU_CFLAGS = + +CFLAGS_OPTIMIZE_V ?= -O0 -g diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/preinstall.am b/c/src/lib/libbsp/epiphany/epiphany_sim/preinstall.am new file mode 100644 index 0000000000..e53b646405 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/preinstall.am @@ -0,0 +1,104 @@ +## Automatically generated by ampolish3 - Do not edit + +if AMPOLISH3 +$(srcdir)/preinstall.am: Makefile.am + $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am +endif + +PREINSTALL_DIRS = +DISTCLEANFILES += $(PREINSTALL_DIRS) + +all-am: $(PREINSTALL_FILES) + +PREINSTALL_FILES = +CLEANFILES = $(PREINSTALL_FILES) + +all-local: $(TMPINSTALL_FILES) + +TMPINSTALL_FILES = +CLEANFILES += $(TMPINSTALL_FILES) + +$(PROJECT_LIB)/$(dirstamp): + @$(MKDIR_P) $(PROJECT_LIB) + @: > $(PROJECT_LIB)/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_LIB)/$(dirstamp) + +$(PROJECT_INCLUDE)/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE) + @: > $(PROJECT_INCLUDE)/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp) + +$(PROJECT_INCLUDE)/bsp/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp + @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp) + +$(PROJECT_INCLUDE)/libcpu/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/libcpu + @: > $(PROJECT_INCLUDE)/libcpu/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + +$(PROJECT_LIB)/bsp_specs: bsp_specs $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/bsp_specs +PREINSTALL_FILES += $(PROJECT_LIB)/bsp_specs + +$(PROJECT_INCLUDE)/bsp.h: include/bsp.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h + +$(PROJECT_INCLUDE)/tm27.h: include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h + +$(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h + +$(PROJECT_INCLUDE)/bsp/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h + +$(PROJECT_INCLUDE)/bsp/linker-symbols.h: ../shared/include/linker-symbols.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/linker-symbols.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/linker-symbols.h + +$(PROJECT_INCLUDE)/bsp/mm.h: ../../../libbsp/shared/include/mm.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mm.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mm.h + +$(PROJECT_INCLUDE)/bsp/utility.h: ../../shared/include/utility.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/utility.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/utility.h + +$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h + +$(PROJECT_INCLUDE)/bsp/irq-info.h: ../../shared/include/irq-info.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-info.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-info.h + +$(PROJECT_INCLUDE)/bsp/stackalloc.h: ../../shared/include/stackalloc.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/stackalloc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/stackalloc.h + +$(PROJECT_INCLUDE)/bsp/console-polled.h: ../../shared/include/console-polled.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/console-polled.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/console-polled.h + +$(PROJECT_INCLUDE)/bsp/irq.h: include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h + +$(PROJECT_INCLUDE)/bspopts.h: include/bspopts.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bspopts.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bspopts.h + +$(PROJECT_LIB)/start.$(OBJEXT): start/start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/start.$(OBJEXT) +TMPINSTALL_FILES += $(PROJECT_LIB)/start.$(OBJEXT) + +$(PROJECT_LIB)/linkcmds: startup/linkcmds $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds +TMPINSTALL_FILES += $(PROJECT_LIB)/linkcmds + diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/start/start.S b/c/src/lib/libbsp/epiphany/epiphany_sim/start/start.S new file mode 100644 index 0000000000..002cb3b764 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/start/start.S @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include + +EXTERN(bsp_section_bss_begin) +EXTERN(bsp_section_bss_end) +EXTERN(ISR_Handler) +EXTERN(bsp_start_vector_table_end) +EXTERN(bsp_start_vector_table_size) +EXTERN(bsp_vector_table_size) +EXTERN(bsp_section_stack_begin) + +PUBLIC(EPIPHANY_Exception_default) +PUBLIC(bsp_start_vector_table_begin) +PUBLIC(start) + +.section .vector, "wax" +TYPE_FUNC(start) +SYM(start): + .balign 4 ; + b .normal_start + + .balign 4 ; 0x4 + b .sw_exception + + .balign 4 ; 0x8 + b .normal_start + + .balign 4 ; 0xc + b .clock_isr + + .balign 4 ; 0x10 + b .timer1_isr + + .balign 4 ; 0x14 + b _EPIPHANY_Exception_default + + .balign 4 ; 0x18 + b _EPIPHANY_Exception_default + + .balign 4 ; 0x1c + b _EPIPHANY_Exception_default + + .balign 4 ; 0x20 + b _EPIPHANY_Exception_default + + .balign 4 ; 0x24 + b _EPIPHANY_Exception_default + +_bsp_start_vector_table_begin: + .word .normal_start /* Reset */ + .word _EPIPHANY_Exception_default /* SW exception */ + .word _EPIPHANY_Exception_default /* Data Page Fault */ + .word _EPIPHANY_Exception_default /* Timer 0 */ + .word _EPIPHANY_Exception_default /* Timer 1 */ + .word _EPIPHANY_Exception_default /* Message int */ + .word _EPIPHANY_Exception_default /* DMA0 int */ + .word _EPIPHANY_Exception_default /* DMA1 int */ + .word _EPIPHANY_Exception_default /* WAND */ + .word _EPIPHANY_Exception_default /* User interrupt */ + +_bsp_start_vector_table_end: + +.size _start, .-_start + +.section .start,"ax" +.align 4 +.type _external_start, %function +.normal_start: + /* Initialize the stack and frame pointers */ + mov sp, %low(bsp_section_stack_begin) + movt sp, %high(bsp_section_stack_begin) + mov fp, sp + +cpu0: + /* Zero .bss section */ + mov r0, %low(bsp_section_bss_begin) + movt r0, %high(bsp_section_bss_begin) + mov r1, sp + mov r2,#0 + mov r3,#0 + +_bss_clear_loop: + strd r2, [r0], +#1 + sub r5, r1, r0 + bne _bss_clear_loop + + /* Clear the reset interrupt flag */ + mov r0, %low(_jump_to_c) + movt r0, %high(_jump_to_c) + movts iret, r0 + rti + +_jump_to_c: + /* Jump to bootcard */ + mov r3, %low(_boot_card) + movt r3, %high(_boot_card) + jalr r3 + + /* Should never reach here */ + idle + +.size .normal_start, .-.normal_start + +.balign 4 +.type .sw_exception, %function +.sw_exception: + idle + +.balign 4 +.type .clock_isr, %function +.clock_isr: + /* + * r62 and r63 are saved here, and restored from _ISR_Handler, they + * and hold vector number and _ISR_Handler address repsectively. + */ + add sp, sp, #-8 + str r62, [sp, #0] + str r63, [sp, #4] + mov r62, 3 + mov r63, %low(_ISR_Handler) + movt r63, %high(_ISR_Handler) + jr r6 + +.balign 4 +.type .timer1_isr, %function +.timer1_isr: + /* + * r62 and r63 are saved here, and restored from _ISR_Handler, they + * and hold vector number and _ISR_Handler address repsectively. + */ + add sp, sp, #-8 + str r62, [sp, 0] + str r63, [sp, 4] + mov r62, 4 + mov r63, %low(_ISR_Handler) + movt r63, %high(_ISR_Handler) + jr r63 + +.balign 4 +TYPE_FUNC(EPIPHANY_Exception_default) +SYM(EPIPHANY_Exception_default): + idle diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/startup/linkcmds b/c/src/lib/libbsp/epiphany/epiphany_sim/startup/linkcmds new file mode 100644 index 0000000000..e06b22f7d6 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/startup/linkcmds @@ -0,0 +1,369 @@ +/** + * @file + * + * @ingroup bsp_linker + * + * @brief Memory map + */ + +/* + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +OUTPUT_FORMAT("elf32-epiphany", "elf32-epiphany", "elf32-epiphany") +OUTPUT_ARCH (epiphany) + +ENTRY (_start) + +MEMORY +{ + VECTOR_RAM (AIW) : ORIGIN = 0x00000000, LENGTH = 0xB0 + LOCAL_MEM (AIW) : ORIGIN = 0x000000B0, LENGTH = 0x00007FC0 /* 32KiB Local memory */ + RAM : ORIGIN = 0x8E000000, LENGTH = 0x01000000 /* 16MiB external RAM */ +} + +REGION_ALIAS ("REGION_START", LOCAL_MEM); +REGION_ALIAS ("REGION_VECTOR", VECTOR_RAM); +REGION_ALIAS ("REGION_TEXT", RAM); +REGION_ALIAS ("REGION_TEXT_LOAD", RAM); +REGION_ALIAS ("REGION_RODATA", RAM); +REGION_ALIAS ("REGION_RODATA_LOAD", RAM); +REGION_ALIAS ("REGION_DATA", RAM); +REGION_ALIAS ("REGION_DATA_LOAD", RAM); +REGION_ALIAS ("REGION_FAST_DATA", RAM); +REGION_ALIAS ("REGION_FAST_DATA_LOAD", RAM); +REGION_ALIAS ("REGION_BSS", RAM); +REGION_ALIAS ("REGION_WORK", RAM); +REGION_ALIAS ("REGION_STACK", RAM); + +/* The following address is used for text output */ +bsp_section_outbut_buffer = 0x8F800000; +bsp_section_vector_begin = 0x00000000; + +/* + * Global symbols that may be defined externally + */ +bsp_vector_table_size = DEFINED (bsp_vector_table_size) ? bsp_vector_table_size : 64; + +bsp_section_xbarrier_align = DEFINED (bsp_section_xbarrier_align) ? bsp_section_xbarrier_align : 1; +bsp_section_robarrier_align = DEFINED (bsp_section_robarrier_align) ? bsp_section_robarrier_align : 1; +bsp_section_rwbarrier_align = DEFINED (bsp_section_rwbarrier_align) ? bsp_section_rwbarrier_align : 1; + +bsp_stack_align = DEFINED (bsp_stack_align) ? bsp_stack_align : 8; + +bsp_stack_main_size = DEFINED (bsp_stack_main_size) ? bsp_stack_main_size : 1024; +bsp_stack_main_size = ALIGN (bsp_stack_main_size, bsp_stack_align); + +_bsp_processor_count = DEFINED (_bsp_processor_count) ? _bsp_processor_count : 1; + +SECTIONS { + + .vector : + { + *(.vector) + . = ALIGN(bsp_vector_table_size); + bsp_section_vector_end = .; + } > REGION_VECTOR AT > REGION_VECTOR + bsp_section_vector_size = bsp_section_vector_end - bsp_section_vector_begin; + bsp_vector_table_begin = bsp_section_vector_begin; + bsp_vector_table_end = bsp_vector_table_begin + bsp_vector_table_size; + + .start : + { + . = ALIGN(8); + bsp_section_start_begin = .; + KEEP (*(.bsp_start_text)) + KEEP (*(.bsp_start_data)) + bsp_section_start_end = .; + } > REGION_START AT > REGION_START + bsp_section_start_size = bsp_section_start_end - bsp_section_start_begin; + +.xbarrier : { + . = ALIGN (bsp_section_xbarrier_align); + } > REGION_VECTOR AT > REGION_VECTOR + +.text : { + . = ALIGN(8); + bsp_section_text_begin = .; + *(.text.unlikely .text.*_unlikely) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + } > REGION_TEXT AT > REGION_TEXT_LOAD + .init : { + KEEP (*(.init)) + } > REGION_TEXT AT > REGION_TEXT_LOAD + .fini : { + KEEP (*(.fini)) + . = ALIGN(8); + bsp_section_text_end = .; + } > REGION_TEXT AT > REGION_TEXT_LOAD + bsp_section_text_size = bsp_section_text_end - bsp_section_text_begin; + bsp_section_text_load_begin = LOADADDR (.text); + bsp_section_text_load_end = bsp_section_text_load_begin + bsp_section_text_size; + +.robarrier : { + . = ALIGN (bsp_section_robarrier_align); + } > REGION_RODATA AT > REGION_RODATA + +.rodata : { + . = ALIGN(8); + bsp_section_rodata_begin = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + } > REGION_RODATA AT > REGION_RODATA_LOAD +.eh_frame : { + KEEP (*(.eh_frame)) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .gcc_except_table : { + *(.gcc_except_table .gcc_except_table.*) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .tdata : { + __TLS_Data_begin = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + __TLS_Data_end = .; + } > REGION_RODATA AT > REGION_RODATA_LOAD + .tbss : { + __TLS_BSS_begin = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + __TLS_BSS_end = .; + } > REGION_RODATA AT > REGION_RODATA_LOAD + __TLS_Data_size = __TLS_Data_end - __TLS_Data_begin; + __TLS_Data_begin = __TLS_Data_size != 0 ? __TLS_Data_begin : __TLS_BSS_begin; + __TLS_Data_end = __TLS_Data_size != 0 ? __TLS_Data_end : __TLS_BSS_begin; + __TLS_BSS_size = __TLS_BSS_end - __TLS_BSS_begin; + __TLS_Size = __TLS_BSS_end - __TLS_Data_begin; + __TLS_Alignment = MAX (ALIGNOF (.tdata), ALIGNOF (.tbss)); + .preinit_array : { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } > REGION_RODATA AT > REGION_RODATA_LOAD + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } > REGION_RODATA AT > REGION_RODATA_LOAD + .fini_array : { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } > REGION_RODATA AT > REGION_RODATA_LOAD + .ctors : { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .data.rel.ro : { + *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) + *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .jcr : { + KEEP (*(.jcr)) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .interp : { + *(.interp) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .note.gnu.build-id : { + *(.note.gnu.build-id) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .hash : { + *(.hash) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .gnu.hash : { + *(.gnu.hash) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .dynsym : { + *(.dynsym) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .dynstr : { + *(.dynstr) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .gnu.version : { + *(.gnu.version) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .gnu.version_d : { + *(.gnu.version_d) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .gnu.version_r : { + *(.gnu.version_r) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .rel.dyn : { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + PROVIDE_HIDDEN (__rela_iplt_start = .); + PROVIDE_HIDDEN (__rela_iplt_end = .); + } > REGION_RODATA AT > REGION_RODATA_LOAD + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + PROVIDE_HIDDEN (__rel_iplt_end = .); + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } > REGION_RODATA AT > REGION_RODATA_LOAD + .rel.plt : { + *(.rel.plt) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .rela.plt : { + *(.rela.plt) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .plt : { + *(.plt) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .iplt : { + *(.iplt) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .dynamic : { + *(.dynamic) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .got : { + *(.got.plt) *(.igot.plt) *(.got) *(.igot) + } > REGION_RODATA AT > REGION_RODATA_LOAD + .rtemsroset : { + /* Special FreeBSD linker set sections */ + __start_set_sysctl_set = .; + *(set_sysctl_*); + __stop_set_sysctl_set = .; + *(set_domain_*); + *(set_pseudo_*); + + KEEP (*(SORT(.rtemsroset.*))) + . = ALIGN(8); + bsp_section_rodata_end = .; + } > REGION_RODATA AT > REGION_RODATA_LOAD + bsp_section_rodata_size = bsp_section_rodata_end - bsp_section_rodata_begin; + bsp_section_rodata_load_begin = LOADADDR (.rodata); + bsp_section_rodata_load_end = bsp_section_rodata_load_begin + bsp_section_rodata_size; + +.rwbarrier : { + . = ALIGN(8); + . = ALIGN (bsp_section_rwbarrier_align); + } > REGION_DATA AT > REGION_DATA + +.data : { + . = ALIGN(8); + bsp_section_data_begin = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } > REGION_DATA AT > REGION_DATA_LOAD + .data1 : { + *(.data1) + } > REGION_DATA AT > REGION_DATA_LOAD + .rtemsrwset : { + KEEP (*(SORT(.rtemsrwset.*))) + . = ALIGN(8); + bsp_section_data_end = .; + } > REGION_DATA AT > REGION_DATA_LOAD + bsp_section_data_size = bsp_section_data_end - bsp_section_data_begin; + bsp_section_data_load_begin = LOADADDR (.data); + bsp_section_data_load_end = bsp_section_data_load_begin + bsp_section_data_size; + + .bss : { + . = ALIGN(8); + bsp_section_bss_begin = .; + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + bsp_section_bss_end = .; + } > REGION_BSS AT > REGION_BSS + bsp_section_bss_size = bsp_section_bss_end - bsp_section_bss_begin; + +.work : { + /* + * The work section will occupy the remaining REGION_WORK region and + * contains the RTEMS work space and heap. + */ + . = ALIGN(8); + bsp_section_work_begin = .; + . += ORIGIN (REGION_WORK) + LENGTH (REGION_WORK) - ABSOLUTE (.); + . = ALIGN(8); + bsp_section_work_end = .; + } > REGION_WORK AT > REGION_WORK + bsp_section_work_size = bsp_section_work_end - bsp_section_work_begin; + + .stack : { + . = ALIGN(8); + bsp_section_stack_begin = .; + . += ORIGIN (REGION_STACK) + LENGTH (REGION_STACK) - ABSOLUTE (.); + . = ALIGN(8); + bsp_section_stack_end = .; + } > REGION_STACK AT > REGION_STACK + bsp_section_stack_size = bsp_section_stack_begin - bsp_section_stack_end; + + _RamBase = ORIGIN (REGION_WORK); + _RamSize = LENGTH (REGION_WORK); + _WorkAreaBase = bsp_section_work_begin; + _HeapSize = 0; +} diff --git a/c/src/lib/libbsp/epiphany/epiphany_sim/timer/timer.c b/c/src/lib/libbsp/epiphany/epiphany_sim/timer/timer.c new file mode 100644 index 0000000000..5df9448e01 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/epiphany_sim/timer/timer.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015 University of York. + * Hesham ALMatary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +extern char bsp_start_vector_table_begin[]; + +bool benchmark_timer_find_average_overhead; + +static void benchmark_timer1_interrupt_handler(void) +{ + unsigned int val = 0xFFFFFFFF; + unsigned int event_type = 0x1; + + /* Embed assembly code for setting timer1 */ + __asm__ __volatile__ ("movts ctimer1, %[val] \t \n" :: [val] "r" (val)); + + __asm__ __volatile__ ("movfs r16, config; \t \n" + "mov r17, %%low(0xfffff0ff);\t \n" + "movt r17, %%high(0xffff0ff);\t \n" + "lsl r18, %[event_type], 0x8; \t \n" + "and r16, r16, r17; \t \n" + "orr r16, r16, r18; \t \n" + "movts config, r16; \t \n" + :: [event_type] "r" (event_type)); +} + +/* Start eCore tiemr 1 usef for profiling and timing analysis */ +void benchmark_timer_initialize( void ) +{ + /* Install interrupt handler for timer 1 */ + + proc_ptr *table = + (proc_ptr *) bsp_start_vector_table_begin; + + table[TIMER1] = benchmark_timer1_interrupt_handler; + + benchmark_timer1_interrupt_handler(); +} + +/* + * The following controls the behavior of benchmark_timer_read(). + * + * AVG_OVEREHAD is the overhead for starting and stopping the timer. It + * is usually deducted from the number returned. + * + * LEAST_VALID is the lowest number this routine should trust. Numbers + * below this are "noise" and zero is returned. + */ + +#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */ + /* (Y countdowns) to start/stop the timer. */ + /* This value is in microseconds. */ +#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */ + +benchmark_timer_t benchmark_timer_read( void ) +{ + uint32_t timer_val = 0; + uint32_t total; + + __asm__ __volatile__ ("movfs %[timer_val], ctimer1 \t \n" + :[timer_val] "=r" (timer_val):); + + total = (0xFFFFFFFF - timer_val); + + if ( benchmark_timer_find_average_overhead == true ) + return total; + else { + if ( total < LEAST_VALID ) + return 0; /* below timer resolution */ + /* + * Somehow convert total into microseconds + */ + return (total - AVG_OVERHEAD); + } +} + +void benchmark_timer_disable_subtracting_average_overhead( + bool find_flag +) +{ + benchmark_timer_find_average_overhead = find_flag; +} diff --git a/c/src/lib/libbsp/epiphany/preinstall.am b/c/src/lib/libbsp/epiphany/preinstall.am new file mode 100644 index 0000000000..dba6cc4d81 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/preinstall.am @@ -0,0 +1,7 @@ +## Automatically generated by ampolish3 - Do not edit + +if AMPOLISH3 +$(srcdir)/preinstall.am: Makefile.am + $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am +endif + diff --git a/c/src/lib/libbsp/epiphany/shared/include/linker-symbols.h b/c/src/lib/libbsp/epiphany/shared/include/linker-symbols.h new file mode 100644 index 0000000000..c218b7ff99 --- /dev/null +++ b/c/src/lib/libbsp/epiphany/shared/include/linker-symbols.h @@ -0,0 +1,81 @@ +#ifndef LIBBSP_EPIPHANY_SHARED_LINKER_SYMBOLS_H +#define LIBBSP_EPIPHANY_SHARED_LINKER_SYMBOLS_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup epiphany_linker Linker Support + * + * @ingroup epiphany_shared + * + * @brief Linker support. + * + * @{ + */ + +#ifndef ASM + #define LINKER_SYMBOL(sym) extern char sym []; +#else + #define LINKER_SYMBOL(sym) .extern sym +#endif + +LINKER_SYMBOL(bsp_section_start_begin) +LINKER_SYMBOL(bsp_section_start_end) +LINKER_SYMBOL(bsp_section_start_size) + +LINKER_SYMBOL(bsp_section_vector_begin) +LINKER_SYMBOL(bsp_section_vector_end) +LINKER_SYMBOL(bsp_section_vector_size) + +LINKER_SYMBOL(bsp_section_text_begin) +LINKER_SYMBOL(bsp_section_text_end) +LINKER_SYMBOL(bsp_section_text_size) +LINKER_SYMBOL(bsp_section_text_load_begin) +LINKER_SYMBOL(bsp_section_text_load_end) + +LINKER_SYMBOL(bsp_section_rodata_begin) +LINKER_SYMBOL(bsp_section_rodata_end) +LINKER_SYMBOL(bsp_section_rodata_size) +LINKER_SYMBOL(bsp_section_rodata_load_begin) +LINKER_SYMBOL(bsp_section_rodata_load_end) + +LINKER_SYMBOL(bsp_section_data_begin) +LINKER_SYMBOL(bsp_section_data_end) +LINKER_SYMBOL(bsp_section_data_size) +LINKER_SYMBOL(bsp_section_data_load_begin) +LINKER_SYMBOL(bsp_section_data_load_end) + +LINKER_SYMBOL(bsp_section_bss_begin) +LINKER_SYMBOL(bsp_section_bss_end) +LINKER_SYMBOL(bsp_section_bss_size) + +LINKER_SYMBOL(bsp_section_work_begin) +LINKER_SYMBOL(bsp_section_work_end) +LINKER_SYMBOL(bsp_section_work_size) + +LINKER_SYMBOL(bsp_section_stack_begin) +LINKER_SYMBOL(bsp_section_stack_end) +LINKER_SYMBOL(bsp_section_stack_size) + +LINKER_SYMBOL(bsp_vector_table_begin) +LINKER_SYMBOL(bsp_vector_table_end) +LINKER_SYMBOL(bsp_vector_table_size) + +LINKER_SYMBOL(bsp_start_vector_table_begin) +LINKER_SYMBOL(bsp_start_vector_table_end) +LINKER_SYMBOL(bsp_start_vector_table_size) + +LINKER_SYMBOL(bsp_translation_table_base) +LINKER_SYMBOL(bsp_translation_table_end) + +LINKER_SYMBOL(_bsp_processor_count) + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_EPIPHANY_SHARED_LINKER_SYMBOLS_H */ -- cgit v1.2.3 From 10504d3ca4d827eaed7c5b2822b3dc75e7b6d11b Mon Sep 17 00:00:00 2001 From: Hesham ALMatary Date: Wed, 20 May 2015 09:51:02 +0100 Subject: doc: Add new documentation section for Epiphany architecture --- doc/cpu_supplement/Makefile.am | 6 +++ doc/cpu_supplement/cpu_supplement.texi | 2 + doc/cpu_supplement/epiphany.t | 75 ++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 doc/cpu_supplement/epiphany.t diff --git a/doc/cpu_supplement/Makefile.am b/doc/cpu_supplement/Makefile.am index 300ff786cc..06ebf48970 100644 --- a/doc/cpu_supplement/Makefile.am +++ b/doc/cpu_supplement/Makefile.am @@ -15,6 +15,7 @@ GENERATED_FILES += general.texi GENERATED_FILES += arm.texi GENERATED_FILES += avr.texi GENERATED_FILES += bfin.texi +GENERATED_FILES += epiphany.texi GENERATED_FILES += h8300.texi GENERATED_FILES += i386.texi GENERATED_FILES += lm32.texi @@ -62,6 +63,11 @@ bfin.texi: bfin.t -u "Top" \ -n "" < $< > $@ +epiphany.texi: epiphany.t + $(BMENU2) -p "" \ + -u "Top" \ + -n "" < $< > $@ + h8300.texi: h8300.t $(BMENU2) -p "" \ -u "Top" \ diff --git a/doc/cpu_supplement/cpu_supplement.texi b/doc/cpu_supplement/cpu_supplement.texi index 5c484d031f..105a54e9a4 100644 --- a/doc/cpu_supplement/cpu_supplement.texi +++ b/doc/cpu_supplement/cpu_supplement.texi @@ -65,6 +65,7 @@ * ARM Specific Information:: * Atmel AVR Specific Information:: * Blackfin Specific Information:: +* Epiphany Specific Information:: * Renesas H8/300 Specific Information:: * Intel/AMD x86 Specific Information:: * Lattice Mico32 Specific Information:: @@ -89,6 +90,7 @@ @include arm.texi @include avr.texi @include bfin.texi +@include epiphany.texi @include h8300.texi @include i386.texi @include lm32.texi diff --git a/doc/cpu_supplement/epiphany.t b/doc/cpu_supplement/epiphany.t new file mode 100644 index 0000000000..a0976cf3b6 --- /dev/null +++ b/doc/cpu_supplement/epiphany.t @@ -0,0 +1,75 @@ +@c +@c Copyright (c) 2015 University of York. +@c Hesham ALMatary + +@ifinfo +@end ifinfo +@chapter Epiphany Specific Information + +This chapter discusses the +@uref{http://adapteva.com/docs/epiphany_sdk_ref.pdf, Epiphany Architecture} +dependencies in this port of RTEMS. Epiphany is a chip that can come with 16 and +64 cores, each of which can run RTEMS separately or they can work together to +run a SMP RTEMS application. + +@subheading Architecture Documents + +For information on the Epiphany architecture refer to the +@uref{http://adapteva.com/docs/epiphany_arch_ref.pdf,Epiphany Architecture Reference}. + +@section Calling Conventions + +Please refer to the +@uref{http://adapteva.com/docs/epiphany_sdk_ref.pdf, Epiphany SDK} +Appendix A: Application Binary Interface + +@subsection Floating Point Unit + +A floating point unit is currently not supported. + +@section Memory Model + +A flat 32-bit memory model is supported, no caches. Each core has its own 32 KiB +strictly ordered local memory along with an access to a shared 32 MiB external +DRAM. + +@section Interrupt Processing + +Every Epiphany core has 10 exception types: + +@itemize @bullet + +@item Reset +@item Software Exception +@item Data Page Fault +@item Timer 0 +@item Timer 1 +@item Message Interrupt +@item DMA0 Interrupt +@item DMA1 Interrupt +@item WANT Interrupt +@item User Interrupt + +@end itemize + +@subsection Interrupt Levels + +There are only two levels: interrupts enabled and interrupts disabled. + +@subsection Interrupt Stack + +The Epiphany RTEMS port uses a dedicated software interrupt stack. +The stack for interrupts is allocated during interrupt driver initialization. +When an interrupt is entered, the _ISR_Handler routine is responsible for +switching from the interrupted task stack to RTEMS software interrupt stack. + +@section Default Fatal Error Processing + +The default fatal error handler for this architecture performs the +following actions: + +@itemize @bullet +@item disables operating system supported interrupts (IRQ), +@item places the error code in @code{r0}, and +@item executes an infinite loop to simulate a halt processor instruction. +@end itemize -- cgit v1.2.3