diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-08-29 09:43:44 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-09-10 10:38:45 +0200 |
commit | 709796209c88e6749320b3096df57f369c2d62be (patch) | |
tree | 072e7cd5cef37aad7404a02344724a4348602f35 /cpukit/score/src/threadunpin.c | |
parent | score: Modify _Scheduler_Unblock() (diff) | |
download | rtems-709796209c88e6749320b3096df57f369c2d62be.tar.bz2 |
score: Add thread pin/unpin support
Add support to temporarily pin a thread to its current processor. This
may be used to access per-processor data structures in critical sections
with enabled thread dispatching, e.g. a pinned thread is allowed to
block.
Update #3508.
Diffstat (limited to 'cpukit/score/src/threadunpin.c')
-rw-r--r-- | cpukit/score/src/threadunpin.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/cpukit/score/src/threadunpin.c b/cpukit/score/src/threadunpin.c new file mode 100644 index 0000000000..bf05790694 --- /dev/null +++ b/cpukit/score/src/threadunpin.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/score/schedulerimpl.h> + +void _Thread_Do_unpin( Thread_Control *executing, Per_CPU_Control *cpu_self ) +{ + ISR_lock_Context state_lock_context; + ISR_lock_Context scheduler_lock_context; + Scheduler_Node *pinned_node; + const Scheduler_Control *pinned_scheduler; + Scheduler_Node *home_node; + const Scheduler_Control *home_scheduler; + const Scheduler_Control *scheduler; + + _Thread_State_acquire( executing, &state_lock_context ); + + executing->Scheduler.pin_level = 0; + + pinned_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( + _Chain_First( &executing->Scheduler.Scheduler_nodes ) + ); + pinned_scheduler = _Scheduler_Node_get_scheduler( pinned_node ); + home_node = _Thread_Scheduler_get_home_node( executing ); + home_scheduler = _Thread_Scheduler_get_home( executing ); + scheduler = pinned_scheduler; + + executing->Scheduler.pinned_scheduler = NULL; + + _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context ); + + if ( _Thread_Is_ready( executing ) ) { + ( *scheduler->Operations.block )( scheduler, executing, pinned_node ); + } + + ( *scheduler->Operations.unpin )( + scheduler, + executing, + pinned_node, + cpu_self + ); + + if ( home_node != pinned_node ) { + _Scheduler_Release_critical( scheduler, &scheduler_lock_context ); + + _Chain_Extract_unprotected( &home_node->Thread.Scheduler_node.Chain ); + _Chain_Prepend_unprotected( + &executing->Scheduler.Scheduler_nodes, + &home_node->Thread.Scheduler_node.Chain + ); + scheduler = home_scheduler; + + _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context ); + } + + if ( _Thread_Is_ready( executing ) ) { + ( *scheduler->Operations.unblock )( scheduler, executing, home_node ); + } + + _Scheduler_Release_critical( scheduler, &scheduler_lock_context ); + + _Thread_State_release( executing, &state_lock_context ); +} |