diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-03-04 08:02:19 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-03-05 11:36:45 +0100 |
commit | 7d6e94b12ab94f13d3e769702d50f91be7d5884b (patch) | |
tree | 2e2db2c1bb80c1f287f2c4c25f819ffa8b958704 /cpukit/rtems/src | |
parent | score: Add thread wait flags (diff) | |
download | rtems-7d6e94b12ab94f13d3e769702d50f91be7d5884b.tar.bz2 |
score: Implement fine-grained locking for events
Use the ISR lock of the thread object to protect the event state and
use the Giant lock only for the blocking operations.
Update #2273.
Diffstat (limited to 'cpukit/rtems/src')
-rw-r--r-- | cpukit/rtems/src/event.c | 3 | ||||
-rw-r--r-- | cpukit/rtems/src/eventdata.c | 23 | ||||
-rw-r--r-- | cpukit/rtems/src/eventreceive.c | 13 | ||||
-rw-r--r-- | cpukit/rtems/src/eventseize.c | 77 | ||||
-rw-r--r-- | cpukit/rtems/src/eventsend.c | 8 | ||||
-rw-r--r-- | cpukit/rtems/src/eventsurrender.c | 139 | ||||
-rw-r--r-- | cpukit/rtems/src/eventtimeout.c | 90 | ||||
-rw-r--r-- | cpukit/rtems/src/systemeventreceive.c | 13 | ||||
-rw-r--r-- | cpukit/rtems/src/systemeventsend.c | 8 | ||||
-rw-r--r-- | cpukit/rtems/src/tasks.c | 2 |
10 files changed, 191 insertions, 185 deletions
diff --git a/cpukit/rtems/src/event.c b/cpukit/rtems/src/event.c index 3a1359e595..7ec44d741d 100644 --- a/cpukit/rtems/src/event.c +++ b/cpukit/rtems/src/event.c @@ -22,9 +22,6 @@ void _Event_Manager_initialization( void ) { - _Event_Sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; - _System_event_Sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; - /* * Register the MP Process Packet routine. */ diff --git a/cpukit/rtems/src/eventdata.c b/cpukit/rtems/src/eventdata.c deleted file mode 100644 index 93fa4737ac..0000000000 --- a/cpukit/rtems/src/eventdata.c +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @file - * - * @brief Instantiate RTEMS Event Data - * @ingroup ClassicEvent - */ - -/* - * 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 - -#define RTEMS_EVENT_EXTERN - -#include <rtems/rtems/eventimpl.h> diff --git a/cpukit/rtems/src/eventreceive.c b/cpukit/rtems/src/eventreceive.c index 49fdb2a9c0..07e1c574df 100644 --- a/cpukit/rtems/src/eventreceive.c +++ b/cpukit/rtems/src/eventreceive.c @@ -21,7 +21,7 @@ #include <rtems/rtems/eventimpl.h> #include <rtems/rtems/tasks.h> #include <rtems/score/statesimpl.h> -#include <rtems/score/threaddispatch.h> +#include <rtems/score/threadimpl.h> rtems_status_code rtems_event_receive( rtems_event_set event_in, @@ -33,12 +33,12 @@ rtems_status_code rtems_event_receive( rtems_status_code sc; if ( event_out != NULL ) { - Thread_Control *executing = _Thread_Get_executing(); + ISR_lock_Context lock_context; + Thread_Control *executing = _Thread_Acquire_executing( &lock_context ); RTEMS_API_Control *api = executing->API_Extensions[ THREAD_API_RTEMS ]; Event_Control *event = &api->Event; if ( !_Event_sets_Is_empty( event_in ) ) { - _Thread_Disable_dispatch(); _Event_Seize( event_in, option_set, @@ -46,14 +46,15 @@ rtems_status_code rtems_event_receive( event_out, executing, event, - &_Event_Sync_state, - STATES_WAITING_FOR_EVENT + THREAD_WAIT_CLASS_EVENT, + STATES_WAITING_FOR_EVENT, + &lock_context ); - _Thread_Enable_dispatch(); sc = executing->Wait.return_code; } else { *event_out = event->pending_events; + _Objects_Release_and_ISR_enable( &executing->Object, &lock_context ); sc = RTEMS_SUCCESSFUL; } } else { diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index ca7c111ab0..59a2b6256f 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -31,24 +31,25 @@ */ void _Event_Seize( - rtems_event_set event_in, - rtems_option option_set, - rtems_interval ticks, - rtems_event_set *event_out, - Thread_Control *executing, - Event_Control *event, - Thread_blocking_operation_States *sync_state, - States_Control wait_state + rtems_event_set event_in, + rtems_option option_set, + rtems_interval ticks, + rtems_event_set *event_out, + Thread_Control *executing, + Event_Control *event, + Thread_Wait_flags wait_class, + States_Control block_state, + ISR_lock_Context *lock_context ) { - rtems_event_set seized_events; - rtems_event_set pending_events; - ISR_Level level; - Thread_blocking_operation_States current_sync_state; + rtems_event_set seized_events; + rtems_event_set pending_events; + bool success; + Thread_Wait_flags intend_to_block; + Per_CPU_Control *cpu_self; executing->Wait.return_code = RTEMS_SUCCESSFUL; - _ISR_Disable( level ); pending_events = event->pending_events; seized_events = _Event_sets_Get( pending_events, event_in ); @@ -56,18 +57,20 @@ void _Event_Seize( (seized_events == event_in || _Options_Is_any( option_set )) ) { event->pending_events = _Event_sets_Clear( pending_events, seized_events ); - _ISR_Enable( level ); + _Objects_Release_and_ISR_enable( &executing->Object, lock_context ); *event_out = seized_events; return; } if ( _Options_Is_no_wait( option_set ) ) { - _ISR_Enable( level ); + _Objects_Release_and_ISR_enable( &executing->Object, lock_context ); executing->Wait.return_code = RTEMS_UNSATISFIED; *event_out = seized_events; return; } + intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK; + /* * Note what we are waiting for BEFORE we enter the critical section. * The interrupt critical section management code needs this to be @@ -76,41 +79,39 @@ void _Event_Seize( * NOTE: Since interrupts are disabled, this isn't that much of an * issue but better safe than sorry. */ - executing->Wait.option = option_set; - executing->Wait.count = event_in; - executing->Wait.return_argument = event_out; - - *sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + executing->Wait.option = option_set; + executing->Wait.count = event_in; + executing->Wait.return_argument = event_out; + _Thread_Wait_flags_set( executing, intend_to_block ); - _ISR_Enable( level ); + cpu_self = _Objects_Release_and_thread_dispatch_disable( + &executing->Object, + lock_context + ); + _Giant_Acquire( cpu_self ); if ( ticks ) { _Watchdog_Initialize( &executing->Timer, _Event_Timeout, executing->Object.id, - sync_state + NULL ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); } - _Thread_Set_state( executing, wait_state ); + _Thread_Set_state( executing, block_state ); - _ISR_Disable( level ); - - current_sync_state = *sync_state; - *sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; - if ( current_sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { - _ISR_Enable( level ); - return; + success = _Thread_Wait_flags_try_change( + executing, + intend_to_block, + wait_class | THREAD_WAIT_STATE_BLOCKED + ); + if ( !success ) { + _Watchdog_Remove( &executing->Timer ); + _Thread_Unblock( executing ); } - /* - * An interrupt completed the thread's blocking request. - * The blocking thread was satisfied by an ISR or timed out. - * - * WARNING! Entering with interrupts disabled and returning with interrupts - * enabled! - */ - _Thread_blocking_operation_Cancel( current_sync_state, executing, level ); + _Giant_Release( cpu_self ); + _Thread_Dispatch_enable( cpu_self ); } diff --git a/cpukit/rtems/src/eventsend.c b/cpukit/rtems/src/eventsend.c index 89bc3e111c..bb9ca3344d 100644 --- a/cpukit/rtems/src/eventsend.c +++ b/cpukit/rtems/src/eventsend.c @@ -31,8 +31,9 @@ rtems_status_code rtems_event_send( Thread_Control *thread; Objects_Locations location; RTEMS_API_Control *api; + ISR_lock_Context lock_context; - thread = _Thread_Get( id, &location ); + thread = _Thread_Acquire( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: api = thread->API_Extensions[ THREAD_API_RTEMS ]; @@ -40,10 +41,9 @@ rtems_status_code rtems_event_send( thread, event_in, &api->Event, - &_Event_Sync_state, - STATES_WAITING_FOR_EVENT + THREAD_WAIT_CLASS_EVENT, + &lock_context ); - _Objects_Put( &thread->Object ); sc = RTEMS_SUCCESSFUL; break; #ifdef RTEMS_MULTIPROCESSING diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index cc3350187e..824912b38d 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -23,75 +23,100 @@ #include <rtems/score/threadimpl.h> #include <rtems/score/watchdogimpl.h> -void _Event_Surrender( - Thread_Control *the_thread, - rtems_event_set event_in, - Event_Control *event, - Thread_blocking_operation_States *sync_state, - States_Control wait_state +static void _Event_Satisfy( + Thread_Control *the_thread, + Event_Control *event, + rtems_event_set pending_events, + rtems_event_set seized_events +) +{ + event->pending_events = _Event_sets_Clear( pending_events, seized_events ); + *(rtems_event_set *) the_thread->Wait.return_argument = seized_events; +} + +static bool _Event_Is_satisfied( + const Thread_Control *the_thread, + rtems_event_set pending_events, + rtems_event_set *seized_events ) { - ISR_Level level; - rtems_event_set pending_events; - rtems_event_set event_condition; - rtems_event_set seized_events; rtems_option option_set; + rtems_event_set event_condition; option_set = the_thread->Wait.option; + event_condition = the_thread->Wait.count; + *seized_events = _Event_sets_Get( pending_events, event_condition ); - _ISR_Disable( level ); - _Event_sets_Post( event_in, &event->pending_events ); - pending_events = event->pending_events; + return !_Event_sets_Is_empty( *seized_events ) + && ( *seized_events == event_condition || _Options_Is_any( option_set ) ); +} - /* - * At this point the event condition is a speculative quantity. Later state - * checks will show if the thread actually waits for an event. - */ - event_condition = the_thread->Wait.count; +void _Event_Surrender( + Thread_Control *the_thread, + rtems_event_set event_in, + Event_Control *event, + Thread_Wait_flags wait_class, + ISR_lock_Context *lock_context +) +{ + rtems_event_set pending_events; + rtems_event_set seized_events; + Thread_Wait_flags wait_flags; + bool unblock; + + _Event_sets_Post( event_in, &event->pending_events ); + pending_events = event->pending_events; - seized_events = _Event_sets_Get( pending_events, event_condition ); + wait_flags = _Thread_Wait_flags_get( the_thread ); if ( - !_Event_sets_Is_empty( seized_events ) - && ( seized_events == event_condition || _Options_Is_any( option_set ) ) + ( wait_flags & THREAD_WAIT_CLASS_MASK ) == wait_class + && _Event_Is_satisfied( the_thread, pending_events, &seized_events ) ) { - /* - * If we are sending to the executing thread, then we have a critical - * section issue to deal with. The entity sending to the executing thread - * can be either the executing thread or an ISR. In case it is the - * executing thread, then the blocking operation state is not equal to - * THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED. - */ - if ( _Thread_Is_executing( the_thread ) && - *sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { - event->pending_events = _Event_sets_Clear( - pending_events, - seized_events - ); - the_thread->Wait.count = 0; - *(rtems_event_set *)the_thread->Wait.return_argument = seized_events; - *sync_state = THREAD_BLOCKING_OPERATION_SATISFIED; - } else if ( _States_Are_set( the_thread->current_state, wait_state ) ) { - event->pending_events = _Event_sets_Clear( - pending_events, - seized_events + Thread_Wait_flags intend_to_block; + Thread_Wait_flags blocked; + bool success; + + 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_INTERRUPT_SATISFIED + ); + if ( success ) { + _Event_Satisfy( the_thread, event, pending_events, seized_events ); + unblock = false; + } else if ( _Thread_Wait_flags_get( the_thread ) == blocked ) { + _Event_Satisfy( the_thread, event, pending_events, seized_events ); + _Thread_Wait_flags_set( + the_thread, + wait_class | THREAD_WAIT_STATE_SATISFIED ); - the_thread->Wait.count = 0; - *(rtems_event_set *)the_thread->Wait.return_argument = seized_events; - - _ISR_Flash( level ); - - if ( !_Watchdog_Is_active( &the_thread->Timer ) ) { - _ISR_Enable( level ); - _Thread_Unblock( the_thread ); - } else { - _Watchdog_Deactivate( &the_thread->Timer ); - _ISR_Enable( level ); - (void) _Watchdog_Remove( &the_thread->Timer ); - _Thread_Unblock( the_thread ); - } - return; + unblock = true; + } else { + unblock = false; } + } else { + unblock = false; + } + + if ( unblock ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Objects_Release_and_thread_dispatch_disable( + &the_thread->Object, + lock_context + ); + _Giant_Acquire( cpu_self ); + + _Watchdog_Remove( &the_thread->Timer ); + _Thread_Unblock( the_thread ); + + _Giant_Release( cpu_self ); + _Thread_Dispatch_enable( cpu_self ); + } else { + _Objects_Release_and_ISR_enable( &the_thread->Object, lock_context ); } - _ISR_Enable( level ); } diff --git a/cpukit/rtems/src/eventtimeout.c b/cpukit/rtems/src/eventtimeout.c index 11d2f118b3..295f0c5b5f 100644 --- a/cpukit/rtems/src/eventtimeout.c +++ b/cpukit/rtems/src/eventtimeout.c @@ -26,55 +26,61 @@ void _Event_Timeout( void *arg ) { - Thread_Control *the_thread; - Objects_Locations location; - ISR_Level level; - Thread_blocking_operation_States *sync_state; + Thread_Control *the_thread; + Objects_Locations location; + 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; - sync_state = arg; - - the_thread = _Thread_Get( id, &location ); + the_thread = _Thread_Acquire( id, &location, &lock_context ); switch ( location ) { - case OBJECTS_LOCAL: + 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_INTERRUPT_TIMEOUT + ); - /* - * If the event manager 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 ); - /* - * Verify that the thread is still waiting for the event condition. - * This test is necessary to avoid state corruption if the timeout - * happens after the event condition is satisfied in - * _Event_Surrender(). A satisfied event condition is indicated with - * count set to zero. - */ - if ( !the_thread->Wait.count ) { - _ISR_Enable( level ); - _Objects_Put_without_thread_dispatch( &the_thread->Object ); - return; - } + 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_TIMEOUT + ); + unblock = true; + } else { + unblock = false; + } - the_thread->Wait.count = 0; - if ( _Thread_Is_executing( the_thread ) ) { - if ( *sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) - *sync_state = THREAD_BLOCKING_OPERATION_TIMEOUT; - } + if ( unblock ) { + Per_CPU_Control *cpu_self; - the_thread->Wait.return_code = RTEMS_TIMEOUT; - _ISR_Enable( level ); - _Thread_Unblock( the_thread ); - _Objects_Put_without_thread_dispatch( &the_thread->Object ); - break; + cpu_self = _Objects_Release_and_thread_dispatch_disable( + &the_thread->Object, + &lock_context + ); + _Giant_Acquire( cpu_self ); + + _Thread_Unblock( the_thread ); + _Giant_Release( cpu_self ); + _Thread_Dispatch_enable( cpu_self ); + } else { + _Objects_Release_and_ISR_enable( &the_thread->Object, &lock_context ); + } + + break; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* impossible */ #endif diff --git a/cpukit/rtems/src/systemeventreceive.c b/cpukit/rtems/src/systemeventreceive.c index c24e19a8ef..394b26e0a8 100644 --- a/cpukit/rtems/src/systemeventreceive.c +++ b/cpukit/rtems/src/systemeventreceive.c @@ -27,7 +27,7 @@ #include <rtems/rtems/eventimpl.h> #include <rtems/rtems/tasks.h> #include <rtems/score/statesimpl.h> -#include <rtems/score/threaddispatch.h> +#include <rtems/score/threadimpl.h> rtems_status_code rtems_event_system_receive( rtems_event_set event_in, @@ -39,12 +39,12 @@ rtems_status_code rtems_event_system_receive( rtems_status_code sc; if ( event_out != NULL ) { - Thread_Control *executing = _Thread_Get_executing(); + ISR_lock_Context lock_context; + Thread_Control *executing = _Thread_Acquire_executing( &lock_context ); RTEMS_API_Control *api = executing->API_Extensions[ THREAD_API_RTEMS ]; Event_Control *event = &api->System_event; if ( !_Event_sets_Is_empty( event_in ) ) { - _Thread_Disable_dispatch(); _Event_Seize( event_in, option_set, @@ -52,14 +52,15 @@ rtems_status_code rtems_event_system_receive( event_out, executing, event, - &_System_event_Sync_state, - STATES_WAITING_FOR_SYSTEM_EVENT + THREAD_WAIT_CLASS_SYSTEM_EVENT, + STATES_WAITING_FOR_SYSTEM_EVENT, + &lock_context ); - _Thread_Enable_dispatch(); sc = executing->Wait.return_code; } else { *event_out = event->pending_events; + _Objects_Release_and_ISR_enable( &executing->Object, &lock_context ); sc = RTEMS_SUCCESSFUL; } } else { diff --git a/cpukit/rtems/src/systemeventsend.c b/cpukit/rtems/src/systemeventsend.c index b2d55524e7..d35127d4bf 100644 --- a/cpukit/rtems/src/systemeventsend.c +++ b/cpukit/rtems/src/systemeventsend.c @@ -37,8 +37,9 @@ rtems_status_code rtems_event_system_send( Thread_Control *thread; Objects_Locations location; RTEMS_API_Control *api; + ISR_lock_Context lock_context; - thread = _Thread_Get( id, &location ); + thread = _Thread_Acquire( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: api = thread->API_Extensions[ THREAD_API_RTEMS ]; @@ -46,10 +47,9 @@ rtems_status_code rtems_event_system_send( thread, event_in, &api->System_event, - &_System_event_Sync_state, - STATES_WAITING_FOR_SYSTEM_EVENT + THREAD_WAIT_CLASS_SYSTEM_EVENT, + &lock_context ); - _Objects_Put( &thread->Object ); sc = RTEMS_SUCCESSFUL; break; #ifdef RTEMS_MULTIPROCESSING diff --git a/cpukit/rtems/src/tasks.c b/cpukit/rtems/src/tasks.c index c8c0accab0..237a313421 100644 --- a/cpukit/rtems/src/tasks.c +++ b/cpukit/rtems/src/tasks.c @@ -54,8 +54,6 @@ static bool _RTEMS_tasks_Create_extension( api = created->API_Extensions[ THREAD_API_RTEMS ]; - _Event_Initialize( &api->Event ); - _Event_Initialize( &api->System_event ); _ASR_Create( &api->Signal ); _Thread_Action_initialize( &api->Signal_action, _Signal_Action_handler ); #if !defined(RTEMS_SMP) |