[PATCH 5/8] score: Add self-contained mutex implementation

Gedare Bloom gedare at gwu.edu
Fri Jul 24 14:19:41 UTC 2015


What, if any, guidance do we need to give to users about these new
implementations?

Or are they (supposedly) hidden from the API so nothing must be said?

We will need developer documentation.
Gedare

On Thu, Jul 23, 2015 at 8:54 AM, Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
> This mutex implementation uses a thread priority queue with a simple
> priority inheritance mechanism (similar to the object based mutexes)
> without support for timeouts.  The storage space must be supplied by the
> user (16 bytes on 32-bit targets).
> ---
>  cpukit/configure.ac                            |   1 +
>  cpukit/libmisc/monitor/mon-prmisc.c            |   1 +
>  cpukit/score/Makefile.am                       |   1 +
>  cpukit/score/include/rtems/score/statesimpl.h  |   3 +
>  cpukit/score/src/mutex.c                       | 314 +++++++++++++++++++++++++
>  testsuites/sptests/Makefile.am                 |   3 +
>  testsuites/sptests/configure.ac                |   4 +
>  testsuites/sptests/spsyslock01/Makefile.am     |  19 ++
>  testsuites/sptests/spsyslock01/init.c          | 301 ++++++++++++++++++++++++
>  testsuites/sptests/spsyslock01/spsyslock01.doc |  20 ++
>  testsuites/sptests/spsyslock01/spsyslock01.scn |   2 +
>  11 files changed, 669 insertions(+)
>  create mode 100644 cpukit/score/src/mutex.c
>  create mode 100644 testsuites/sptests/spsyslock01/Makefile.am
>  create mode 100644 testsuites/sptests/spsyslock01/init.c
>  create mode 100644 testsuites/sptests/spsyslock01/spsyslock01.doc
>  create mode 100644 testsuites/sptests/spsyslock01/spsyslock01.scn
>
> diff --git a/cpukit/configure.ac b/cpukit/configure.ac
> index c2b8e8d..14ce0f1 100644
> --- a/cpukit/configure.ac
> +++ b/cpukit/configure.ac
> @@ -71,6 +71,7 @@ AC_CHECK_DECLS([ftrylockfile],[AC_CHECK_FUNCS([ftrylockfile])],,[#include <stdio
>  AC_CHECK_HEADERS([envlock.h])
>  AC_CHECK_DECLS([__env_lock],,,[#include <envlock.h>])
>  AC_CHECK_DECLS([__env_unlock],,,[#include <envlock.h>])
> +AC_CHECK_TYPES([struct _Thread_queue_Queue],[],[],[#include <sys/lock.h>])
>
>  # Mandated by POSIX, older newlibs bogusly provided CLOCK_PROCESS_CPUTIME+CLOCK_THREAD_CPUTIME
>  AC_CHECK_DECL([CLOCK_PROCESS_CPUTIME_ID],[],[AC_MSG_ERROR([missing define CLOCK_PROCESS_CPUTIME_ID])],[#include <time.h>])
> diff --git a/cpukit/libmisc/monitor/mon-prmisc.c b/cpukit/libmisc/monitor/mon-prmisc.c
> index 738014f..ae7f75d 100644
> --- a/cpukit/libmisc/monitor/mon-prmisc.c
> +++ b/cpukit/libmisc/monitor/mon-prmisc.c
> @@ -134,6 +134,7 @@ static const rtems_assoc_t rtems_monitor_state_assoc[] = {
>      { "Wseg",   STATES_WAITING_FOR_SEGMENT, 0 },
>      { "Wsem",   STATES_WAITING_FOR_SEMAPHORE, 0 },
>      { "Wsig",   STATES_WAITING_FOR_SIGNAL, 0 },
> +    { "Wslmtx", STATES_WAITING_FOR_SYS_LOCK_MUTEX, 0 },
>      { "Wsysev", STATES_WAITING_FOR_SYSTEM_EVENT, 0 },
>      { "Wterm",  STATES_WAITING_FOR_TERMINATION, 0 },
>      { "Wtime",  STATES_WAITING_FOR_TIME, 0 },
> diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
> index 3e612d4..3c117bb 100644
> --- a/cpukit/score/Makefile.am
> +++ b/cpukit/score/Makefile.am
> @@ -345,6 +345,7 @@ libscore_a_SOURCES += src/apiext.c src/chain.c src/chainappend.c \
>  libscore_a_SOURCES += src/isrisinprogress.c
>  libscore_a_SOURCES += src/debugisownerofallocator.c
>  libscore_a_SOURCES += src/profilingisrentryexit.c
> +libscore_a_SOURCES += src/mutex.c
>  libscore_a_SOURCES += src/once.c
>  libscore_a_SOURCES += src/resourceiterate.c
>  libscore_a_SOURCES += src/smpbarrierwait.c
> diff --git a/cpukit/score/include/rtems/score/statesimpl.h b/cpukit/score/include/rtems/score/statesimpl.h
> index d1c402e..4ad8786 100644
> --- a/cpukit/score/include/rtems/score/statesimpl.h
> +++ b/cpukit/score/include/rtems/score/statesimpl.h
> @@ -86,6 +86,8 @@ extern "C" {
>  #define STATES_RESTARTING                      0x800000
>  /** This macro corresponds to a task waiting for a join. */
>  #define STATES_WAITING_FOR_JOIN                0x1000000
> +/** This macro corresponds to a task waiting for a <sys/lock.h> mutex. */
> +#define STATES_WAITING_FOR_SYS_LOCK_MUTEX      0x2000000
>
>  /** This macro corresponds to a task which is in an interruptible
>   *  blocking state.
> @@ -103,6 +105,7 @@ extern "C" {
>                                   STATES_WAITING_FOR_SIGNAL             | \
>                                   STATES_WAITING_FOR_BARRIER            | \
>                                   STATES_WAITING_FOR_BSD_WAKEUP         | \
> +                                 STATES_WAITING_FOR_SYS_LOCK_MUTEX     | \
>                                   STATES_WAITING_FOR_RWLOCK             )
>
>  /** This macro corresponds to a task waiting which is blocked. */
> diff --git a/cpukit/score/src/mutex.c b/cpukit/score/src/mutex.c
> new file mode 100644
> index 0000000..57b50f5
> --- /dev/null
> +++ b/cpukit/score/src/mutex.c
> @@ -0,0 +1,314 @@
> +/*
> + * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
> + *
> + *  embedded brains GmbH
> + *  Dornierstr. 4
> + *  82178 Puchheim
> + *  Germany
> + *  <rtems at embedded-brains.de>
> + *
> + * 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 <sys/lock.h>
> +
> +#include <rtems/score/assert.h>
> +#include <rtems/score/threadimpl.h>
> +#include <rtems/score/threadqimpl.h>
> +
> +#if HAVE_STRUCT__THREAD_QUEUE_QUEUE
> +
> +RTEMS_STATIC_ASSERT(
> +  offsetof( Thread_queue_Queue, heads )
> +    == offsetof( struct _Thread_queue_Queue, _heads ),
> +  THREAD_QUEUE_QUEUE_HEADS
> +);
> +
> +#if defined(RTEMS_SMP)
> +RTEMS_STATIC_ASSERT(
> +  offsetof( Thread_queue_Queue, Lock.next_ticket )
> +    == offsetof( struct _Thread_queue_Queue, _Lock._next_ticket ),
> +  THREAD_QUEUE_QUEUE_NEXT_TICKET
> +);
> +RTEMS_STATIC_ASSERT(
> +  offsetof( Thread_queue_Queue, Lock.now_serving )
> +    == offsetof( struct _Thread_queue_Queue, _Lock._now_serving ),
> +  THREAD_QUEUE_QUEUE_NOW_SERVING
> +);
> +RTEMS_STATIC_ASSERT(
> +  sizeof( Thread_queue_Queue )
> +    == sizeof( struct _Thread_queue_Queue ),
> +  THREAD_QUEUE_QUEUE_SIZE_SMP
> +);
> +#else
> +RTEMS_STATIC_ASSERT(
> +  sizeof( Thread_queue_Queue )
> +    == offsetof( struct _Thread_queue_Queue, _Lock._next_ticket ),
> +  THREAD_QUEUE_QUEUE_SIZE_UNI
> +);
> +#endif
> +
> +#define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
> +
> +static Thread_queue_Queue *_Mutex_Get_thread_queue(
> +  struct _Mutex_Control *mutex
> +)
> +{
> +  return (Thread_queue_Queue *) &mutex->_Queue;
> +}
> +
> +static Thread_Control *_Mutex_Queue_acquire(
> +  struct _Mutex_Control *mutex,
> +  ISR_lock_Context *lock_context
> +)
> +{
> +  Thread_Control *executing;
> +
> +  _ISR_lock_ISR_disable( lock_context );
> +  executing = _Thread_Executing;
> +  _Thread_queue_Queue_acquire_critical(
> +    _Mutex_Get_thread_queue( mutex ),
> +    &executing->Potpourri_stats,
> +    lock_context
> +  );
> +
> +  return executing;
> +}
> +
> +static void _Mutex_Queue_release(
> +  struct _Mutex_Control *mutex,
> +  ISR_lock_Context *lock_context
> +)
> +{
> +  _Thread_queue_Queue_release(
> +    _Mutex_Get_thread_queue( mutex ),
> +    lock_context
> +  );
> +}
> +
> +static void _Mutex_Acquire_more(
> +  struct _Mutex_Control *mutex,
> +  Thread_Control *owner,
> +  Thread_Control *executing,
> +  ISR_lock_Context *lock_context
> +)
> +{
> +  /* Priority inheritance */
> +  _Thread_Raise_priority( owner, executing->current_priority );
> +
> +  _Thread_queue_Enqueue_critical(
> +    _Mutex_Get_thread_queue( mutex ),
> +    MUTEX_TQ_OPERATIONS,
> +    executing,
> +    STATES_WAITING_FOR_SYS_LOCK_MUTEX,
> +    0,
> +    0,
> +    lock_context
> +  );
> +}
> +
> +static void _Mutex_Release_more(
> +  struct _Mutex_Control *mutex,
> +  Thread_Control *executing,
> +  Thread_queue_Heads *heads,
> +  bool keep_priority,
> +  ISR_lock_Context *lock_context
> +)
> +{
> +  if (heads != NULL) {
> +    const Thread_queue_Operations *operations;
> +    Thread_Control *first;
> +
> +    operations = MUTEX_TQ_OPERATIONS;
> +    first = ( *operations->first )( heads );
> +
> +    mutex->_owner = first;
> +    _Thread_queue_Extract_critical(
> +      _Mutex_Get_thread_queue( mutex ),
> +      operations,
> +      first,
> +      lock_context
> +    );
> +  } else {
> +    _Mutex_Queue_release( mutex, lock_context);
> +  }
> +
> +  if ( !keep_priority ) {
> +    Per_CPU_Control *cpu_self;
> +
> +    cpu_self = _Thread_Dispatch_disable();
> +    _Thread_Restore_priority( executing );
> +    _Thread_Dispatch_enable( cpu_self );
> +  }
> +}
> +
> +static void _Mutex_Release_critical(
> +  struct _Mutex_Control *mutex,
> +  Thread_Control *executing,
> +  ISR_lock_Context *lock_context
> +)
> +{
> +  Thread_queue_Heads *heads;
> +  bool keep_priority;
> +
> +  mutex->_owner = NULL;
> +
> +  --executing->resource_count;
> +
> +  /*
> +   * Ensure that the owner resource count is visible to all other
> +   * processors and that we read the latest priority restore
> +   * hint.
> +   */
> +  _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
> +
> +  heads = _Mutex_Get_thread_queue( mutex )->heads;
> +  keep_priority = _Thread_Owns_resources( executing )
> +    || !executing->priority_restore_hint;
> +
> +  if ( __predict_true( heads == NULL && keep_priority ) ) {
> +    _Mutex_Queue_release( mutex, lock_context );
> +  } else {
> +    _Mutex_Release_more(
> +      mutex,
> +      executing,
> +      heads,
> +      keep_priority,
> +      lock_context
> +    );
> +  }
> +}
> +
> +void _Mutex_Acquire( struct _Mutex_Control *mutex )
> +{
> +  ISR_lock_Context lock_context;
> +  Thread_Control *executing;
> +  Thread_Control *owner;
> +
> +  executing = _Mutex_Queue_acquire( mutex, &lock_context );
> +
> +  owner = mutex->_owner;
> +  ++executing->resource_count;
> +
> +  if ( __predict_true( owner == NULL ) ) {
> +    mutex->_owner = executing;
> +
> +    _Mutex_Queue_release( mutex, &lock_context );
> +  } else {
> +    _Mutex_Acquire_more( mutex, owner, executing, &lock_context );
> +  }
> +}
> +
> +int _Mutex_Try_acquire( struct _Mutex_Control *mutex )
> +{
> +  int success;
> +  ISR_lock_Context lock_context;
> +  Thread_Control *executing;
> +  Thread_Control *owner;
> +
> +  executing = _Mutex_Queue_acquire( mutex, &lock_context );
> +
> +  owner = mutex->_owner;
> +
> +  if ( __predict_true( owner == NULL ) ) {
> +    mutex->_owner = executing;
> +    ++executing->resource_count;
> +    success = 1;
> +  } else {
> +    success = 0;
> +  }
> +
> +  _Mutex_Queue_release( mutex, &lock_context );
> +
> +  return success;
> +}
> +
> +void _Mutex_Release( struct _Mutex_Control *mutex )
> +{
> +  ISR_lock_Context lock_context;
> +  Thread_Control *executing;
> +
> +  executing = _Mutex_Queue_acquire( mutex, &lock_context );
> +
> +  _Assert( mutex->_owner == executing );
> +
> +  _Mutex_Release_critical( mutex, executing, &lock_context );
> +}
> +
> +void _Mutex_recursive_Acquire( struct _Mutex_recursive_Control *mutex )
> +{
> +  ISR_lock_Context lock_context;
> +  Thread_Control *executing;
> +  Thread_Control *owner;
> +
> +  executing = _Mutex_Queue_acquire( &mutex->_Mutex, &lock_context );
> +
> +  owner = mutex->_Mutex._owner;
> +
> +  if ( __predict_true( owner == NULL ) ) {
> +    mutex->_Mutex._owner = executing;
> +    ++executing->resource_count;
> +    _Mutex_Queue_release( &mutex->_Mutex, &lock_context );
> +  } else if ( owner == executing ) {
> +    ++mutex->_nest_level;
> +    _Mutex_Queue_release( &mutex->_Mutex, &lock_context );
> +  } else {
> +    _Mutex_Acquire_more( &mutex->_Mutex, owner, executing, &lock_context );
> +  }
> +}
> +
> +int _Mutex_recursive_Try_acquire( struct _Mutex_recursive_Control *mutex )
> +{
> +  int success;
> +  ISR_lock_Context lock_context;
> +  Thread_Control *executing;
> +  Thread_Control *owner;
> +
> +  executing = _Mutex_Queue_acquire( &mutex->_Mutex, &lock_context );
> +
> +  owner = mutex->_Mutex._owner;
> +
> +  if ( __predict_true( owner == NULL ) ) {
> +    mutex->_Mutex._owner = executing;
> +    ++executing->resource_count;
> +    success = 1;
> +  } else if ( owner == executing ) {
> +    ++mutex->_nest_level;
> +    success = 1;
> +  } else {
> +    success = 0;
> +  }
> +
> +  _Mutex_Queue_release( &mutex->_Mutex, &lock_context );
> +
> +  return success;
> +}
> +
> +void _Mutex_recursive_Release( struct _Mutex_recursive_Control *mutex )
> +{
> +  ISR_lock_Context lock_context;
> +  Thread_Control *executing;
> +  unsigned int nest_level;
> +
> +  executing = _Mutex_Queue_acquire( &mutex->_Mutex, &lock_context );
> +
> +  _Assert( mutex->_Mutex._owner == executing );
> +
> +  nest_level = mutex->_nest_level;
> +
> +  if ( __predict_true( nest_level == 0 ) ) {
> +    _Mutex_Release_critical( &mutex->_Mutex, executing, &lock_context );
> +  } else {
> +    mutex->_nest_level = nest_level - 1;
> +
> +    _Mutex_Queue_release( &mutex->_Mutex, &lock_context );
> +  }
> +}
> +
> +#endif /* HAVE_STRUCT__THREAD_QUEUE_QUEUE */
> diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
> index 8811623..d012019 100644
> --- a/testsuites/sptests/Makefile.am
> +++ b/testsuites/sptests/Makefile.am
> @@ -37,6 +37,9 @@ if HAS_SMP
>  else
>  _SUBDIRS += sp29
>  endif
> +if HAS__THREAD_QUEUE_QUEUE
> +_SUBDIRS += spsyslock01
> +endif
>  _SUBDIRS += sptasknopreempt01
>  _SUBDIRS += spintrcritical23
>  _SUBDIRS += sptimecounter01
> diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
> index 99e9b89..be69f09 100644
> --- a/testsuites/sptests/configure.ac
> +++ b/testsuites/sptests/configure.ac
> @@ -30,6 +30,9 @@ AM_CONDITIONAL([HAS_CPLUSPLUS],[test $HAS_CPLUSPLUS = "yes"])
>  # FIXME: We should get rid of this. It's a cludge.
>  AC_CHECK_SIZEOF([time_t])
>
> +AC_CHECK_TYPES([struct _Thread_queue_Queue],[],[],[#include <sys/lock.h>])
> +AM_CONDITIONAL(HAS__THREAD_QUEUE_QUEUE,test x"${ac_cv_type_struct__Thread_queue_Queue}" = x"yes")
> +
>  # Added to newlib pthreads for RTEMS SMP (np), may not be present
>  AC_CHECK_HEADERS([sys/cpuset.h])
>  AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes")
> @@ -40,6 +43,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes")
>
>  # Explicitly list all Makefiles here
>  AC_CONFIG_FILES([Makefile
> +spsyslock01/Makefile
>  sptasknopreempt01/Makefile
>  spintrcritical23/Makefile
>  sptimecounter01/Makefile
> diff --git a/testsuites/sptests/spsyslock01/Makefile.am b/testsuites/sptests/spsyslock01/Makefile.am
> new file mode 100644
> index 0000000..7fb3a01
> --- /dev/null
> +++ b/testsuites/sptests/spsyslock01/Makefile.am
> @@ -0,0 +1,19 @@
> +rtems_tests_PROGRAMS = spsyslock01
> +spsyslock01_SOURCES = init.c
> +
> +dist_rtems_tests_DATA = spsyslock01.scn spsyslock01.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 = $(spsyslock01_OBJECTS)
> +LINK_LIBS = $(spsyslock01_LDLIBS)
> +
> +spsyslock01$(EXEEXT): $(spsyslock01_OBJECTS) $(spsyslock01_DEPENDENCIES)
> +       @rm -f spsyslock01$(EXEEXT)
> +       $(make-exe)
> +
> +include $(top_srcdir)/../automake/local.am
> diff --git a/testsuites/sptests/spsyslock01/init.c b/testsuites/sptests/spsyslock01/init.c
> new file mode 100644
> index 0000000..7d93676
> --- /dev/null
> +++ b/testsuites/sptests/spsyslock01/init.c
> @@ -0,0 +1,301 @@
> +/*
> + * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
> + *
> + *  embedded brains GmbH
> + *  Dornierstr. 4
> + *  82178 Puchheim
> + *  Germany
> + *  <rtems at embedded-brains.de>
> + *
> + * 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.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +  #include "config.h"
> +#endif
> +
> +#include "tmacros.h"
> +
> +#include <sys/lock.h>
> +#include <string.h>
> +
> +const char rtems_test_name[] = "SPSYSLOCK 1";
> +
> +#define EVENT_MTX_ACQUIRE RTEMS_EVENT_0
> +
> +#define EVENT_MTX_RELEASE RTEMS_EVENT_1
> +
> +#define EVENT_MTX_PRIO_INV RTEMS_EVENT_2
> +
> +#define EVENT_MTX_DEADLOCK RTEMS_EVENT_3
> +
> +#define EVENT_REC_MTX_ACQUIRE RTEMS_EVENT_4
> +
> +#define EVENT_REC_MTX_RELEASE RTEMS_EVENT_5
> +
> +#define EVENT_REC_MTX_PRIO_INV RTEMS_EVENT_6
> +
> +typedef struct {
> +  rtems_id high;
> +  rtems_id mid;
> +  rtems_id low;
> +  struct _Mutex_Control mtx;
> +  struct _Mutex_recursive_Control rec_mtx;
> +  bool flag;
> +} test_context;
> +
> +static test_context test_instance;
> +
> +static void send_events(test_context *ctx, rtems_event_set events)
> +{
> +  rtems_status_code sc;
> +
> +  sc = rtems_event_send(ctx->high, events);
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +}
> +
> +static void test_initialization(test_context *ctx)
> +{
> +  struct _Mutex_Control mtx = _MUTEX_INITIALIZER;
> +  struct _Mutex_recursive_Control rec_mtx = _MUTEX_RECURSIVE_INITIALIZER;
> +
> +  _Mutex_Initialize(&ctx->mtx);
> +  _Mutex_recursive_Initialize(&ctx->rec_mtx);
> +
> +  rtems_test_assert(memcmp(&mtx, &ctx->mtx, sizeof(mtx)) == 0);
> +  rtems_test_assert(memcmp(&rec_mtx, &ctx->rec_mtx, sizeof(rec_mtx)) == 0);
> +
> +  _Mutex_Destroy(&mtx);
> +  _Mutex_recursive_Destroy(&rec_mtx);
> +}
> +
> +static void test_recursive_acquire_normal(test_context *ctx)
> +{
> +  struct _Mutex_Control *mtx = &ctx->mtx;
> +  int success;
> +
> +  success = _Mutex_Try_acquire(mtx);
> +  rtems_test_assert(success == 1);
> +
> +  success = _Mutex_Try_acquire(mtx);
> +  rtems_test_assert(success == 0);
> +
> +  _Mutex_Release(mtx);
> +
> +  success = _Mutex_Try_acquire(mtx);
> +  rtems_test_assert(success == 1);
> +
> +  _Mutex_Release(mtx);
> +
> +  _Mutex_Acquire(mtx);
> +
> +  success = _Mutex_Try_acquire(mtx);
> +  rtems_test_assert(success == 0);
> +
> +  _Mutex_Release(mtx);
> +
> +  send_events(ctx, EVENT_MTX_ACQUIRE);
> +
> +  success = _Mutex_Try_acquire(mtx);
> +  rtems_test_assert(success == 0);
> +
> +  send_events(ctx, EVENT_MTX_RELEASE);
> +}
> +
> +static void test_recursive_acquire_recursive(test_context *ctx)
> +{
> +  struct _Mutex_recursive_Control *mtx = &ctx->rec_mtx;
> +  int success;
> +
> +  success = _Mutex_recursive_Try_acquire(mtx);
> +  rtems_test_assert(success == 1);
> +
> +  _Mutex_recursive_Acquire(mtx);
> +
> +  success = _Mutex_recursive_Try_acquire(mtx);
> +  rtems_test_assert(success == 1);
> +
> +  _Mutex_recursive_Release(mtx);
> +  _Mutex_recursive_Release(mtx);
> +  _Mutex_recursive_Release(mtx);
> +
> +  send_events(ctx, EVENT_REC_MTX_ACQUIRE);
> +
> +  success = _Mutex_recursive_Try_acquire(mtx);
> +  rtems_test_assert(success == 0);
> +
> +  send_events(ctx, EVENT_REC_MTX_RELEASE);
> +}
> +
> +static void test_prio_inv_normal(test_context *ctx)
> +{
> +  struct _Mutex_Control *mtx = &ctx->mtx;
> +
> +  _Mutex_Acquire(mtx);
> +  ctx->flag = false;
> +  send_events(ctx, EVENT_MTX_PRIO_INV);
> +  rtems_test_assert(!ctx->flag);
> +  _Mutex_Release(mtx);
> +  rtems_test_assert(ctx->flag);
> +}
> +
> +static void test_prio_inv_recursive(test_context *ctx)
> +{
> +  struct _Mutex_recursive_Control *mtx = &ctx->rec_mtx;
> +
> +  _Mutex_recursive_Acquire(mtx);
> +  ctx->flag = false;
> +  send_events(ctx, EVENT_REC_MTX_PRIO_INV);
> +  rtems_test_assert(!ctx->flag);
> +  _Mutex_recursive_Release(mtx);
> +  rtems_test_assert(ctx->flag);
> +}
> +
> +static void mid_task(rtems_task_argument arg)
> +{
> +  rtems_test_assert(0);
> +}
> +
> +static void high_task(rtems_task_argument arg)
> +{
> +  test_context *ctx = &test_instance;
> +  rtems_status_code sc;
> +
> +  sc = rtems_task_start(ctx->mid, mid_task, 0);
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +  sc = rtems_task_suspend(ctx->mid);
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +  while (true) {
> +    rtems_event_set events;
> +
> +    sc = rtems_event_receive(
> +      RTEMS_ALL_EVENTS,
> +      RTEMS_EVENT_ANY | RTEMS_WAIT,
> +      RTEMS_NO_TIMEOUT,
> +      &events
> +    );
> +    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +    if ((events & EVENT_MTX_ACQUIRE) != 0) {
> +      _Mutex_Acquire(&ctx->mtx);
> +    }
> +
> +    if ((events & EVENT_MTX_RELEASE) != 0) {
> +      _Mutex_Release(&ctx->mtx);
> +    }
> +
> +    if ((events & EVENT_MTX_PRIO_INV) != 0) {
> +      sc = rtems_task_resume(ctx->mid);
> +      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +      _Mutex_Acquire(&ctx->mtx);
> +      ctx->flag = true;
> +      _Mutex_Release(&ctx->mtx);
> +
> +      sc = rtems_task_suspend(ctx->mid);
> +      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +    }
> +
> +    if ((events & EVENT_MTX_DEADLOCK) != 0) {
> +      struct _Mutex_Control dead = _MUTEX_INITIALIZER;
> +
> +      _Mutex_Acquire(&dead);
> +      _Mutex_Acquire(&dead);
> +    }
> +
> +    if ((events & EVENT_REC_MTX_ACQUIRE) != 0) {
> +      _Mutex_recursive_Acquire(&ctx->rec_mtx);
> +    }
> +
> +    if ((events & EVENT_REC_MTX_RELEASE) != 0) {
> +      _Mutex_recursive_Release(&ctx->rec_mtx);
> +    }
> +
> +    if ((events & EVENT_REC_MTX_PRIO_INV) != 0) {
> +      sc = rtems_task_resume(ctx->mid);
> +      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +      _Mutex_recursive_Acquire(&ctx->rec_mtx);
> +      ctx->flag = true;
> +      _Mutex_recursive_Release(&ctx->rec_mtx);
> +
> +      sc = rtems_task_suspend(ctx->mid);
> +      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +    }
> +  }
> +}
> +
> +static void test(void)
> +{
> +  test_context *ctx = &test_instance;
> +  rtems_status_code sc;
> +
> +  test_initialization(ctx);
> +
> +  ctx->low = rtems_task_self();
> +
> +  sc = rtems_task_create(
> +    rtems_build_name('M', 'I', 'D', ' '),
> +    2,
> +    RTEMS_MINIMUM_STACK_SIZE,
> +    RTEMS_DEFAULT_MODES,
> +    RTEMS_DEFAULT_ATTRIBUTES,
> +    &ctx->mid
> +  );
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +  sc = rtems_task_create(
> +    rtems_build_name('H', 'I', 'G', 'H'),
> +    1,
> +    RTEMS_MINIMUM_STACK_SIZE,
> +    RTEMS_DEFAULT_MODES,
> +    RTEMS_DEFAULT_ATTRIBUTES,
> +    &ctx->high
> +  );
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +  sc = rtems_task_start(ctx->high, high_task, 0);
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +  test_recursive_acquire_normal(ctx);
> +  test_recursive_acquire_recursive(ctx);
> +  test_prio_inv_normal(ctx);
> +  test_prio_inv_recursive(ctx);
> +
> +  send_events(ctx, EVENT_MTX_DEADLOCK);
> +
> +  _Mutex_Destroy(&ctx->mtx);
> +  _Mutex_recursive_Destroy(&ctx->rec_mtx);
> +}
> +
> +static void Init(rtems_task_argument arg)
> +{
> +  TEST_BEGIN();
> +
> +  test();
> +
> +  TEST_END();
> +  rtems_test_exit(0);
> +}
> +
> +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
> +
> +#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
> +
> +#define CONFIGURE_MAXIMUM_TASKS 3
> +
> +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
> +
> +#define CONFIGURE_INIT_TASK_PRIORITY 3
> +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
> +
> +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
> +
> +#define CONFIGURE_INIT
> +
> +#include <rtems/confdefs.h>
> diff --git a/testsuites/sptests/spsyslock01/spsyslock01.doc b/testsuites/sptests/spsyslock01/spsyslock01.doc
> new file mode 100644
> index 0000000..440759d
> --- /dev/null
> +++ b/testsuites/sptests/spsyslock01/spsyslock01.doc
> @@ -0,0 +1,20 @@
> +This file describes the directives and concepts tested by this test set.
> +
> +test set name: spsyslock01
> +
> +directives:
> +
> +  - _Mutex_Initialize()
> +  - _Mutex_Acquire()
> +  - _Mutex_Try_acquire()
> +  - _Mutex_Release()
> +  - _Mutex_Destroy()
> +  - _Mutex_recursive_Initialize()
> +  - _Mutex_recursive_Acquire()
> +  - _Mutex_recursive_Try_acquire()
> +  - _Mutex_recursive_Release()
> +  - _Mutex_recursive_Destroy()
> +
> +concepts:
> +
> +  - Ensure that self-contained mutexes and recursive mutexes work.
> diff --git a/testsuites/sptests/spsyslock01/spsyslock01.scn b/testsuites/sptests/spsyslock01/spsyslock01.scn
> new file mode 100644
> index 0000000..f8c05f7
> --- /dev/null
> +++ b/testsuites/sptests/spsyslock01/spsyslock01.scn
> @@ -0,0 +1,2 @@
> +*** BEGIN OF TEST SPSYSLOCK 1 ***
> +*** END OF TEST SPSYSLOCK 1 ***
> --
> 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