[PATCH 5/8] score: Add self-contained mutex implementation
Sebastian Huber
sebastian.huber at embedded-brains.de
Thu Jul 23 12:54:45 UTC 2015
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
More information about the devel
mailing list