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 + * <rt...@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@.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 + * <rt...@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@rtems.org http://lists.rtems.org/mailman/listinfo/devel