[PATCH] sptests: add test to demonstrate bug in strict order mutex

Gedare Bloom gedare at rtems.org
Sun May 19 21:41:09 UTC 2013


Please see www.rtems.org/pr2124

This test demonstrates an unbounded priority inversion in the current
implementation of the RTEMS Strict Order Mutex. When compiled with
strict order mutex, the highest priority task (TA03) is kept blocked
at S0 until a lower priority task (TA02) exits.

The pattern is that the low priority task acquires the outer and inner
mutexes, then the mid priority task blocks on the inner mutex, and the
high priority task blocks on the outer mutex. Because of priority
inherianace, the low priority task gets the high priority while in the
inner mutex, but when it releases the inner mutex, the strict order
steps down its priority to the priority it had when it acquired the
inner mutex, i.e. it's low priority. So the low priority task still
holds the outer mutex and the high priority task is blocked, but the
mid priority task is allowed to execute. The mid priority can execute
arbitrarily long, creating an unbounded priority inversion.

Until this bug is fixed, the strict order mutex option should be avoided.

-Gedare

On Sun, May 19, 2013 at 5:30 PM, Gedare Bloom <gedare at rtems.org> wrote:
> ---
>  testsuites/sptests/Makefile.am         |    2 +-
>  testsuites/sptests/configure.ac        |    1 +
>  testsuites/sptests/spsem02/Makefile.am |   21 ++++
>  testsuites/sptests/spsem02/init.c      |  190 ++++++++++++++++++++++++++++++++
>  testsuites/sptests/spsem02/spsem02.doc |   23 ++++
>  testsuites/sptests/spsem02/spsem02.scn |   22 ++++
>  6 files changed, 258 insertions(+), 1 deletion(-)
>  create mode 100644 testsuites/sptests/spsem02/Makefile.am
>  create mode 100644 testsuites/sptests/spsem02/init.c
>  create mode 100644 testsuites/sptests/spsem02/spsem02.doc
>  create mode 100644 testsuites/sptests/spsem02/spsem02.scn
>
> diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
> index 9acf477..8e61968 100644
> --- a/testsuites/sptests/Makefile.am
> +++ b/testsuites/sptests/Makefile.am
> @@ -25,7 +25,7 @@ SUBDIRS = \
>      spintrcritical09 spintrcritical10 spintrcritical11 spintrcritical12 \
>      spintrcritical13 spintrcritical14 spintrcritical15 spintrcritical16 \
>      spintrcritical17 spintrcritical18 spmkdir spmountmgr01 spheapprot \
> -    spsem01 spsimplesched01 spsimplesched02 spsimplesched03 spnsext01 \
> +    spsem01 spsem02 spsimplesched01 spsimplesched02 spsimplesched03 spnsext01 \
>      spedfsched01 spedfsched02 spedfsched03 \
>      spcbssched01 spcbssched02 spcbssched03 spqreslib sptimespec01 \
>      spatomic01 spatomic02 spatomic03 spatomic04 spatomic05 \
> diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
> index 9f40fa1..bbdda18 100644
> --- a/testsuites/sptests/configure.ac
> +++ b/testsuites/sptests/configure.ac
> @@ -189,6 +189,7 @@ spprivenv01/Makefile
>  spqreslib/Makefile
>  sprbtree01/Makefile
>  spsem01/Makefile
> +spsem02/Makefile
>  spsimplesched01/Makefile
>  spsimplesched02/Makefile
>  spsimplesched03/Makefile
> diff --git a/testsuites/sptests/spsem02/Makefile.am b/testsuites/sptests/spsem02/Makefile.am
> new file mode 100644
> index 0000000..a4df8dd
> --- /dev/null
> +++ b/testsuites/sptests/spsem02/Makefile.am
> @@ -0,0 +1,21 @@
> +
> +rtems_tests_PROGRAMS = spsem02
> +spsem02_SOURCES = init.c
> +
> +dist_rtems_tests_DATA = spsem02.scn
> +dist_rtems_tests_DATA += spsem02.doc
> +
> +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
> +include $(top_srcdir)/../automake/compile.am
> +include $(top_srcdir)/../automake/leaf.am
> +
> +AM_CPPFLAGS += -I$(top_srcdir)/../support/include
> +
> +LINK_OBJS = $(spsem02_OBJECTS)
> +LINK_LIBS = $(spsem02_LDLIBS)
> +
> +spsem02$(EXEEXT): $(spsem02_OBJECTS) $(spsem02_DEPENDENCIES)
> +       @rm -f spsem02$(EXEEXT)
> +       $(make-exe)
> +
> +include $(top_srcdir)/../automake/local.am
> diff --git a/testsuites/sptests/spsem02/init.c b/testsuites/sptests/spsem02/init.c
> new file mode 100644
> index 0000000..524fce7
> --- /dev/null
> +++ b/testsuites/sptests/spsem02/init.c
> @@ -0,0 +1,190 @@
> +/*
> + * Copyright (c) 2013 Gedare Bloom.
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.com/license/LICENSE.
> + */
> +
> +#include <rtems.h>
> +
> +#include <stdio.h>
> +#include "tmacros.h"
> +
> +/* configuration information */
> +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
> +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
> +#define CONFIGURE_EXTRA_TASK_STACKS (RTEMS_MINIMUM_STACK_SIZE * 3)
> +#define CONFIGURE_MAXIMUM_TASKS 4
> +#define CONFIGURE_MAXIMUM_SEMAPHORES 2
> +#define CONFIGURE_INIT
> +#include <rtems/confdefs.h>
> +
> +rtems_task Task01(rtems_task_argument ignored);
> +rtems_task Task02(rtems_task_argument ignored);
> +rtems_task Task03(rtems_task_argument ignored);
> +rtems_task Init(rtems_task_argument ignored);
> +
> +static int getprio(void)
> +{
> +  rtems_status_code status;
> +  rtems_task_priority pri;
> +
> +  status = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &pri);
> +  directive_failed( status, "rtems_task_set_priority");
> +  return (int)pri;
> +}
> +
> +rtems_id   Task_id[3];
> +rtems_name Task_name[3];
> +
> +rtems_id   sem_id[2];
> +rtems_name sem_name[2];
> +
> +rtems_task Init(rtems_task_argument ignored)
> +{
> +  rtems_status_code status;
> +  rtems_attribute sem_attr;
> +
> +  printf("\n*** TEST SEM02 ***\n");
> +
> +  sem_attr = RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY;
> +
> +  sem_name[0] = rtems_build_name( 'S','0',' ',' ');
> +  status = rtems_semaphore_create(
> +    sem_name[0],
> +    1,
> +    sem_attr,
> +    0,
> +    &sem_id[0]
> +  );
> +  directive_failed( status, "rtems_semaphore_create of S0");
> +  printf("init: S0 created\n");
> +
> +  sem_name[1] = rtems_build_name( 'S','1',' ',' ');
> +  status = rtems_semaphore_create(
> +    sem_name[1],
> +    1,
> +    sem_attr,
> +    0,
> +    &sem_id[1]
> +  );
> +  directive_failed( status, "rtems_semaphore_create of S1");
> +  printf("init: S1 created\n");
> +
> +  Task_name[0] = rtems_build_name( 'T','A','0','1');
> +  status = rtems_task_create(
> +    Task_name[0],
> +    36,
> +    RTEMS_MINIMUM_STACK_SIZE*2,
> +    RTEMS_DEFAULT_MODES,
> +    RTEMS_DEFAULT_ATTRIBUTES,
> +    &Task_id[0]
> +  );
> +  directive_failed( status, "rtems_task_create of TA01");
> +  printf("init: TA01 created with priority 36\n");
> +
> +  Task_name[1] = rtems_build_name( 'T','A','0','2');
> +  status = rtems_task_create(
> +    Task_name[1],
> +    34,
> +    RTEMS_MINIMUM_STACK_SIZE*2,
> +    RTEMS_DEFAULT_MODES,
> +    RTEMS_DEFAULT_ATTRIBUTES,
> +    &Task_id[1]
> +  );
> +  directive_failed( status , "rtems_task_create of TA02\n");
> +  printf("init: TA02 created with priority 34\n");
> +
> +  Task_name[2] = rtems_build_name( 'T','A','0','3');
> +  status = rtems_task_create(
> +    Task_name[2],
> +    32,
> +    RTEMS_MINIMUM_STACK_SIZE*2,
> +    RTEMS_DEFAULT_MODES,
> +    RTEMS_DEFAULT_ATTRIBUTES,
> +    &Task_id[2]
> +  );
> +  directive_failed( status , "rtems_task_create of TA03\n");
> +  printf("init: TA03 created with priority 32\n");
> +
> +  status = rtems_task_start( Task_id[0], Task01, 0);
> +  directive_failed( status, "rtems_task_start of TA01");
> +
> +  status = rtems_task_delete( RTEMS_SELF);
> +  directive_failed( status, "rtems_task_delete of INIT");
> +}
> +
> +/* Task01 starts with priority 36 */
> +rtems_task Task01(rtems_task_argument ignored)
> +{
> +  rtems_status_code status;
> +  printf("TA01: started with priority %d\n", getprio());
> +
> +  status = rtems_semaphore_obtain( sem_id[0], RTEMS_WAIT, 0 );
> +  directive_failed( status, "rtems_semaphore_obtain of S0\n");
> +  printf("TA01: priority %d, holding S0\n", getprio());
> +
> +  status = rtems_semaphore_obtain( sem_id[1], RTEMS_WAIT, 0 );
> +  directive_failed( status, "rtems_semaphore_obtain of S1");
> +  printf("TA01: priority %d, holding S0, S1\n", getprio());
> +
> +  /* Start Task 2 (TA02) with priority 34. It will run immediately. */
> +  status = rtems_task_start( Task_id[1], Task02, 0);
> +  directive_failed( status, "rtems_task_start of TA02\n");
> +
> +  /* Start Task 3 (TA03) with priority 32. It will run immediately. */
> +  status = rtems_task_start( Task_id[2], Task03, 0);
> +  directive_failed( status, "rtems_task_start of TA03\n");
> +  printf("TA01: priority %d, holding S0, S1\n", getprio());
> +
> +  status = rtems_semaphore_release(sem_id[1]);
> +  directive_failed( status, "rtems_semaphore_release of S1\n");
> +  printf("TA01: priority %d, holding S0\n", getprio());
> +
> +  status = rtems_semaphore_release(sem_id[0]);
> +  directive_failed( status, "rtems_semaphore_release of S0\n");
> +  printf("TA01: priority %d\n", getprio());
> +
> +  printf("TA01: exiting\n");
> +  printf("*** END OF SEM02 ***\n");
> +  status = rtems_task_delete( RTEMS_SELF);
> +  directive_failed( status, "rtems_task_delete TA01");
> +}
> +
> +/* TA02 starts at Task02 with priority 34 */
> +rtems_task Task02(rtems_task_argument ignored)
> +{
> +  rtems_status_code status;
> +
> +  printf("TA02: started with priority %d\n", getprio());
> +
> +  /* Obtain S1, which should be held by TA01 by now */
> +  status = rtems_semaphore_obtain( sem_id[1], RTEMS_WAIT, 0 );
> +  directive_failed( status, " rtems_semaphore_obtain S1");
> +  printf("TA02: priority %d, holding S1\n", getprio());
> +
> +  printf("TA02: exiting\n");
> +  status = rtems_task_delete( RTEMS_SELF);
> +  directive_failed( status, "rtems_task_delete TA02");
> +}
> +
> +/* Task03 starts with priority 32 */
> +rtems_task Task03(rtems_task_argument ignored)
> +{
> +  rtems_status_code status;
> +  printf("TA03: started with priority %d\n", getprio());
> +
> +  status = rtems_semaphore_obtain( sem_id[0], RTEMS_WAIT, 0 );
> +  directive_failed( status, "rtems_semaphore_obtain of S0\n");
> +  printf("TA03: priority %d, holding S0\n", getprio());
> +
> +  status = rtems_semaphore_release(sem_id[0]);
> +  directive_failed( status, "rtems_semaphore_release of S0\n");
> +  printf("TA03: priority %d\n", getprio());
> +
> +  printf("TA03: exiting\n");
> +  status = rtems_task_delete( RTEMS_SELF);
> +  directive_failed( status, "rtems_task_delete TA03");
> +}
> diff --git a/testsuites/sptests/spsem02/spsem02.doc b/testsuites/sptests/spsem02/spsem02.doc
> new file mode 100644
> index 0000000..95ff65a
> --- /dev/null
> +++ b/testsuites/sptests/spsem02/spsem02.doc
> @@ -0,0 +1,23 @@
> +This test demonstrates priority inheritance with multiple locks and threads.
> +
> +The scenario consists of 3 tasks of different priority and 2 semaphore/mutexes
> +using priority inheritance. The scenario is:
> +
> +Task 1 has priority 36. Task 2 has priority 34. Task 3 has priority 32.
> +
> +1. Task 1 obtains semaphore S1.
> +2. Task 1 obtains semaphore S2.
> +3. Task 2 preempts Task 1.
> +4. Task 2 blocks on S2.  Task 1 inherits priority 34.
> +5. Task 1 resumes.
> +6. Task 3 preempts Task 1.
> +7. Task 3 blocks on S1. Task 1 inherits priority 32.
> +8. Task 1 resumes. Task 1 releases S2. Task 1 continues with priority 32.
> +9. Task 1 releases S0.
> +10. Task 3 resumes.
> +11. Task 3 releases S0 and exits.
> +12. Task 2 resumes.
> +13. Task 2 releases S1 and exits.
> +14. Task 1 resumes.
> +15. Task 1 exits.
> +
> diff --git a/testsuites/sptests/spsem02/spsem02.scn b/testsuites/sptests/spsem02/spsem02.scn
> new file mode 100644
> index 0000000..5b8d03d
> --- /dev/null
> +++ b/testsuites/sptests/spsem02/spsem02.scn
> @@ -0,0 +1,22 @@
> +*** TEST SEM02 ***
> +init: S0 created
> +init: S1 created
> +init: TA01 created with priority 36
> +init: TA02 created with priority 34
> +init: TA03 created with priority 32
> +TA01: started with priority 36
> +TA01: priority 36, holding S0
> +TA01: priority 36, holding S0, S1
> +TA02: started with priority 34
> +TA03: started with priority 32
> +TA01: priority 32, holding S0, S1
> +TA01: priority 32, holding S0
> +TA03: priority 32, holding S0
> +TA03: priority 32
> +TA03: exiting
> +TA02: priority 34, holding S1
> +TA02: exiting
> +TA01: priority 36
> +TA01: exiting
> +*** END OF SEM02 ***
> +
> --
> 1.7.9.5
>



More information about the devel mailing list