[PATCH 4/4] score: Implement priority boosting

Gedare Bloom gedare at rtems.org
Thu Sep 3 15:22:15 UTC 2015


3 and 4 look good.

On Thu, Sep 3, 2015 at 8:01 AM, Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
> ---
>  cpukit/score/include/rtems/score/threadimpl.h  | 31 +++++++++++++
>  cpukit/score/include/rtems/score/threadqimpl.h | 25 +++++++++++
>  cpukit/score/src/coremutexseize.c              |  2 +-
>  cpukit/score/src/coremutexsurrender.c          |  1 +
>  cpukit/score/src/mutex.c                       | 15 ++++---
>  cpukit/score/src/threadchangepriority.c        | 34 ++++++++++++++
>  cpukit/score/src/threadqops.c                  | 22 ++++++++++
>  doc/user/sem.t                                 |  5 +++
>  doc/user/smp.t                                 |  6 ++-
>  testsuites/smptests/smpmutex01/init.c          | 61 +++++++++++++++++++++++---
>  10 files changed, 189 insertions(+), 13 deletions(-)
>
> diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
> index 4656881..1092b65 100644
> --- a/cpukit/score/include/rtems/score/threadimpl.h
> +++ b/cpukit/score/include/rtems/score/threadimpl.h
> @@ -437,6 +437,37 @@ void _Thread_Raise_priority(
>  );
>
>  /**
> + * @brief Inherit the priority of a thread.
> + *
> + * It changes the current priority of the inheritor thread to the current priority
> + * of the ancestor thread if it is higher than the current priority of the inheritor
> + * thread.  In this case the inheritor thread is appended to its new priority group
> + * in its scheduler instance.
> + *
> + * On SMP configurations, the priority is changed to PRIORITY_PSEUDO_ISR in
> + * case the own schedulers of the inheritor and ancestor thread differ (priority
> + * boosting).
> + *
> + * @param[in] inheritor The thread to inherit the priority.
> + * @param[in] ancestor The thread to bequeath its priority to the inheritor
> + *   thread.
> + */
> +#if defined(RTEMS_SMP)
> +void _Thread_Inherit_priority(
> +  Thread_Control *inheritor,
> +  Thread_Control *ancestor
> +);
> +#else
> +RTEMS_INLINE_ROUTINE void _Thread_Inherit_priority(
> +  Thread_Control *inheritor,
> +  Thread_Control *ancestor
> +)
> +{
> +  _Thread_Raise_priority( inheritor, ancestor->current_priority );
> +}
> +#endif
> +
> +/**
>   * @brief Sets the current to the real priority of a thread.
>   *
>   * Sets the priority restore hint to false.
> diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h
> index bf01eb7..510f886 100644
> --- a/cpukit/score/include/rtems/score/threadqimpl.h
> +++ b/cpukit/score/include/rtems/score/threadqimpl.h
> @@ -522,6 +522,31 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
>  }
>
>  /**
> + * @brief Boosts the priority of the thread if threads of another scheduler
> + * instance are enqueued on the thread queue.
> + *
> + * The thread queue must use the priority waiting discipline.
> + *
> + * @param[in] queue The actual thread queue.
> + * @param[in] the_thread The thread to boost the priority if necessary.
> + */
> +#if defined(RTEMS_SMP)
> +void _Thread_queue_Boost_priority(
> +  Thread_queue_Queue *queue,
> +  Thread_Control     *the_thread
> +);
> +#else
> +RTEMS_INLINE_ROUTINE void _Thread_queue_Boost_priority(
> +  Thread_queue_Queue *queue,
> +  Thread_Control     *the_thread
> +)
> +{
> +  (void) queue;
> +  (void) the_thread;
> +}
> +#endif
> +
> +/**
>   * @brief Compare two thread's priority for RBTree Insertion.
>   *
>   * @param[in] left points to the left thread's RBnode
> diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c
> index ddc5d6b..8059659 100644
> --- a/cpukit/score/src/coremutexseize.c
> +++ b/cpukit/score/src/coremutexseize.c
> @@ -75,7 +75,7 @@ void _CORE_mutex_Seize_interrupt_blocking(
>      _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
>  #endif
>
> -    _Thread_Raise_priority( holder, executing->current_priority );
> +    _Thread_Inherit_priority( holder, executing );
>
>  #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 d3f965d..7d9c57f 100644
> --- a/cpukit/score/src/coremutexsurrender.c
> +++ b/cpukit/score/src/coremutexsurrender.c
> @@ -209,6 +209,7 @@ CORE_mutex_Status _CORE_mutex_Surrender(
>          case CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT:
>            _CORE_mutex_Push_priority( the_mutex, the_thread );
>            the_thread->resource_count++;
> +          _Thread_queue_Boost_priority( &the_mutex->Wait_queue.Queue, the_thread );
>            break;
>          case CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING:
>            _CORE_mutex_Push_priority( the_mutex, the_thread );
> diff --git a/cpukit/score/src/mutex.c b/cpukit/score/src/mutex.c
> index ae637dd..f03bab7 100644
> --- a/cpukit/score/src/mutex.c
> +++ b/cpukit/score/src/mutex.c
> @@ -112,9 +112,7 @@ static void _Mutex_Acquire_slow(
>    ISR_lock_Context  *lock_context
>  )
>  {
> -  /* Priority inheritance */
> -  _Thread_Raise_priority( owner, executing->current_priority );
> -
> +  _Thread_Inherit_priority( owner, executing );
>    _Thread_queue_Enqueue_critical(
>      &mutex->Queue.Queue,
>      MUTEX_TQ_OPERATIONS,
> @@ -136,15 +134,22 @@ static void _Mutex_Release_slow(
>  {
>    if (heads != NULL) {
>      const Thread_queue_Operations *operations;
> -    Thread_Control *first;
> +    Thread_Control                *first;
> +    bool                           unblock;
>
>      operations = MUTEX_TQ_OPERATIONS;
>      first = ( *operations->first )( heads );
>
>      mutex->owner = first;
> -    _Thread_queue_Extract_critical(
> +    unblock = _Thread_queue_Extract_locked(
>        &mutex->Queue.Queue,
>        operations,
> +      first
> +    );
> +    _Thread_queue_Boost_priority( &mutex->Queue.Queue, first );
> +    _Thread_queue_Unblock_critical(
> +      unblock,
> +      &mutex->Queue.Queue,
>        first,
>        lock_context
>      );
> diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
> index 8f5d14f..35e5e5b 100644
> --- a/cpukit/score/src/threadchangepriority.c
> +++ b/cpukit/score/src/threadchangepriority.c
> @@ -110,6 +110,40 @@ void _Thread_Raise_priority(
>    );
>  }
>
> +#if defined(RTEMS_SMP)
> +static bool _Thread_Inherit_priority_filter(
> +  Thread_Control   *inheritor,
> +  Priority_Control *new_priority,
> +  void             *arg
> +)
> +{
> +  Thread_Control *ancestor = arg;
> +
> +  if ( _Scheduler_Get_own( inheritor ) == _Scheduler_Get_own( ancestor ) ) {
> +    *new_priority = ancestor->current_priority;
> +  }
> +
> +  return _Thread_Priority_less_than(
> +    inheritor->current_priority,
> +    *new_priority
> +  );
> +}
> +
> +void _Thread_Inherit_priority(
> +  Thread_Control *inheritor,
> +  Thread_Control *ancestor
> +)
> +{
> +  _Thread_Change_priority(
> +    inheritor,
> +    PRIORITY_PSEUDO_ISR,
> +    ancestor,
> +    _Thread_Inherit_priority_filter,
> +    false
> +  );
> +}
> +#endif
> +
>  static bool _Thread_Restore_priority_filter(
>    Thread_Control   *the_thread,
>    Priority_Control *new_priority,
> diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c
> index 07473f5..7b01779 100644
> --- a/cpukit/score/src/threadqops.c
> +++ b/cpukit/score/src/threadqops.c
> @@ -293,6 +293,28 @@ static Thread_Control *_Thread_queue_Priority_first(
>    return THREAD_RBTREE_NODE_TO_THREAD( first );
>  }
>
> +#if defined(RTEMS_SMP)
> +void _Thread_queue_Boost_priority(
> +  Thread_queue_Queue *queue,
> +  Thread_Control     *the_thread
> +)
> +{
> +  Thread_queue_Heads *heads = queue->heads;
> +
> +  if (
> +    heads != NULL
> +      && (
> +        !_Chain_Has_only_one_node( &heads->Heads.Fifo )
> +          || _RBTree_Is_empty(
> +            &_Thread_queue_Priority_queue( heads, the_thread )->Queue
> +          )
> +      )
> +  ) {
> +    _Thread_Raise_priority( the_thread, PRIORITY_PSEUDO_ISR );
> +  }
> +}
> +#endif
> +
>  const Thread_queue_Operations _Thread_queue_Operations_default = {
>    .priority_change = _Thread_queue_Do_nothing_priority_change,
>    .extract = _Thread_queue_Do_nothing_extract
> diff --git a/doc/user/sem.t b/doc/user/sem.t
> index 6bd22dd..8fbac93 100644
> --- a/doc/user/sem.t
> +++ b/doc/user/sem.t
> @@ -115,6 +115,11 @@ for that resource.  Each time a task blocks attempting to obtain
>  the resource, the task holding the resource may have its
>  priority increased.
>
> +On SMP configurations, in case the task holding the resource and the task that
> +blocks attempting to obtain the resource are in different scheduler instances,
> +the priority of the holder is raised to the pseudo interrupt priority (priority
> +boosting).  The pseudo interrupt priority is the highest priority.
> +
>  RTEMS supports priority inheritance for local, binary
>  semaphores that use the priority task wait queue blocking
>  discipline.   When a task of higher priority than the task
> diff --git a/doc/user/smp.t b/doc/user/smp.t
> index 53fd7b64..2ab9aaf 100644
> --- a/doc/user/smp.t
> +++ b/doc/user/smp.t
> @@ -164,11 +164,13 @@ and instruction caches. With clustered/partitioned scheduling it is possible to
>  honour the cache topology of a system and thus avoid expensive cache
>  synchronization traffic.  It is easy to implement.  The problem is to provide
>  synchronization primitives for inter-partition synchronization. In RTEMS there
> -are currently three means available
> +are currently four means available
>
>  @itemize @bullet
>  @item events,
> - at item message queues, and
> + at item message queues,
> + at item semaphores using the @ref{Semaphore Manager Priority Inheritance}
> +protocol (priority boosting), and
>  @item semaphores using the @ref{Semaphore Manager Multiprocessor Resource
>  Sharing Protocol} (MrsP).
>  @end itemize
> diff --git a/testsuites/smptests/smpmutex01/init.c b/testsuites/smptests/smpmutex01/init.c
> index 1b2a189..80b16fe 100644
> --- a/testsuites/smptests/smpmutex01/init.c
> +++ b/testsuites/smptests/smpmutex01/init.c
> @@ -26,7 +26,7 @@ const char rtems_test_name[] = "SMPMUTEX 1";
>
>  #define PART_COUNT 2
>
> -#define TASK_COUNT 8
> +#define TASK_COUNT 9
>
>  typedef enum {
>    REQ_WAKE_UP_MASTER = RTEMS_EVENT_0,
> @@ -43,7 +43,8 @@ typedef enum {
>    B_4,
>    B_5_0,
>    B_5_1,
> -  H,
> +  H_A,
> +  H_B,
>    NONE
>  } task_id;
>
> @@ -111,15 +112,21 @@ static rtems_event_set wait_for_events(void)
>    return events;
>  }
>
> -static void sync_with_helper(test_context *ctx)
> +static void sync_with_helper_by_id(test_context *ctx, task_id id)
>  {
>    rtems_event_set events;
>
> -  send_event(ctx, H, REQ_WAKE_UP_HELPER);
> +  send_event(ctx, id, REQ_WAKE_UP_HELPER);
>    events = wait_for_events();
>    rtems_test_assert(events == REQ_WAKE_UP_MASTER);
>  }
>
> +static void sync_with_helper(test_context *ctx)
> +{
> +  sync_with_helper_by_id(ctx, H_A);
> +  sync_with_helper_by_id(ctx, H_B);
> +}
> +
>  static void request(test_context *ctx, task_id id, request_id req)
>  {
>    send_event(ctx, id, req);
> @@ -159,6 +166,24 @@ static void check_generations(test_context *ctx, task_id a, task_id b)
>    }
>  }
>
> +static void assert_prio(
> +  test_context *ctx,
> +  task_id id,
> +  rtems_task_priority expected
> +)
> +{
> +  rtems_task_priority actual;
> +  rtems_status_code sc;
> +
> +  sc = rtems_task_set_priority(
> +    ctx->tasks[id],
> +    RTEMS_CURRENT_PRIORITY,
> +    &actual
> +  );
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +  rtems_test_assert(expected == actual);
> +}
> +
>  static void helper(rtems_task_argument arg)
>  {
>    test_context *ctx = &test_instance;
> @@ -202,7 +227,8 @@ static void test(void)
>    start_task(ctx, B_4, worker, 4, SCHED_B);
>    start_task(ctx, B_5_0, worker, 5, SCHED_B);
>    start_task(ctx, B_5_1, worker, 5, SCHED_B);
> -  start_task(ctx, H, helper, 6, SCHED_B);
> +  start_task(ctx, H_A, helper, 3, SCHED_A);
> +  start_task(ctx, H_B, helper, 6, SCHED_B);
>
>    sc = rtems_semaphore_create(
>      rtems_build_name(' ', 'M', 'T', 'X'),
> @@ -216,8 +242,10 @@ static void test(void)
>    obtain(ctx);
>    request(ctx, A_1, REQ_MTX_OBTAIN);
>    check_generations(ctx, NONE, NONE);
> +  assert_prio(ctx, M, 1);
>    release(ctx);
>    check_generations(ctx, A_1, NONE);
> +  assert_prio(ctx, M, 3);
>    request(ctx, A_1, REQ_MTX_RELEASE);
>    check_generations(ctx, A_1, NONE);
>
> @@ -226,8 +254,11 @@ static void test(void)
>    request(ctx, A_1, REQ_MTX_OBTAIN);
>    request(ctx, A_2_1, REQ_MTX_OBTAIN);
>    check_generations(ctx, NONE, NONE);
> +  assert_prio(ctx, M, 1);
>    release(ctx);
>    check_generations(ctx, A_1, NONE);
> +  assert_prio(ctx, M, 3);
> +  assert_prio(ctx, A_1, 1);
>    request(ctx, A_1, REQ_MTX_RELEASE);
>    check_generations(ctx, A_1, A_2_0);
>    request(ctx, A_2_0, REQ_MTX_RELEASE);
> @@ -240,8 +271,10 @@ static void test(void)
>    request(ctx, B_4, REQ_MTX_OBTAIN);
>    request(ctx, B_5_1, REQ_MTX_OBTAIN);
>    check_generations(ctx, NONE, NONE);
> +  assert_prio(ctx, M, 0);
>    release(ctx);
>    sync_with_helper(ctx);
> +  assert_prio(ctx, M, 3);
>    check_generations(ctx, B_4, NONE);
>    request(ctx, B_4, REQ_MTX_RELEASE);
>    check_generations(ctx, B_4, B_5_0);
> @@ -252,26 +285,44 @@ static void test(void)
>
>    obtain(ctx);
>    request(ctx, A_2_0, REQ_MTX_OBTAIN);
> +  check_generations(ctx, NONE, NONE);
> +  assert_prio(ctx, M, 2);
>    request(ctx, B_5_0, REQ_MTX_OBTAIN);
> +  check_generations(ctx, NONE, NONE);
> +  assert_prio(ctx, M, 0);
>    request(ctx, B_5_1, REQ_MTX_OBTAIN);
>    request(ctx, B_4, REQ_MTX_OBTAIN);
>    request(ctx, A_2_1, REQ_MTX_OBTAIN);
>    request(ctx, A_1, REQ_MTX_OBTAIN);
>    check_generations(ctx, NONE, NONE);
>    release(ctx);
> +  sync_with_helper(ctx);
>    check_generations(ctx, A_1, NONE);
> +  assert_prio(ctx, M, 3);
> +  assert_prio(ctx, A_1, 0);
>    request(ctx, A_1, REQ_MTX_RELEASE);
>    check_generations(ctx, A_1, B_4);
> +  assert_prio(ctx, A_1, 1);
> +  assert_prio(ctx, B_4, 0);
>    request(ctx, B_4, REQ_MTX_RELEASE);
>    check_generations(ctx, B_4, A_2_0);
> +  assert_prio(ctx, B_4, 4);
> +  assert_prio(ctx, A_2_0, 0);
>    request(ctx, A_2_0, REQ_MTX_RELEASE);
>    check_generations(ctx, A_2_0, B_5_0);
> +  assert_prio(ctx, A_2_0, 2);
> +  assert_prio(ctx, B_5_0, 0);
>    request(ctx, B_5_0, REQ_MTX_RELEASE);
>    check_generations(ctx, B_5_0, A_2_1);
> +  assert_prio(ctx, B_5_0, 5);
> +  assert_prio(ctx, A_2_1, 0);
>    request(ctx, A_2_1, REQ_MTX_RELEASE);
>    check_generations(ctx, A_2_1, B_5_1);
> +  assert_prio(ctx, A_2_1, 2);
> +  assert_prio(ctx, B_5_1, 5);
>    request(ctx, B_5_1, REQ_MTX_RELEASE);
>    check_generations(ctx, B_5_1, NONE);
> +  assert_prio(ctx, B_5_1, 5);
>  }
>
>  static void Init(rtems_task_argument arg)
> --
> 1.8.4.5
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel



More information about the devel mailing list