summaryrefslogtreecommitdiffstats
path: root/cpukit/rtems/src/eventsurrender.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-03-04 08:02:19 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-03-05 11:36:45 +0100
commit7d6e94b12ab94f13d3e769702d50f91be7d5884b (patch)
tree2e2db2c1bb80c1f287f2c4c25f819ffa8b958704 /cpukit/rtems/src/eventsurrender.c
parentscore: Add thread wait flags (diff)
downloadrtems-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/eventsurrender.c')
-rw-r--r--cpukit/rtems/src/eventsurrender.c139
1 files changed, 82 insertions, 57 deletions
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 );
}