--- cpukit/libmisc/monitor/mon-prmisc.c | 1 + cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/statesimpl.h | 3 + cpukit/score/src/semaphore.c | 118 +++++++++++++++++++++++++ testsuites/sptests/spsyslock01/init.c | 26 ++++++ testsuites/sptests/spsyslock01/spsyslock01.doc | 5 ++ 6 files changed, 154 insertions(+) create mode 100644 cpukit/score/src/semaphore.c
diff --git a/cpukit/libmisc/monitor/mon-prmisc.c b/cpukit/libmisc/monitor/mon-prmisc.c index ae7f75d..4656ed2 100644 --- a/cpukit/libmisc/monitor/mon-prmisc.c +++ b/cpukit/libmisc/monitor/mon-prmisc.c @@ -135,6 +135,7 @@ static const rtems_assoc_t rtems_monitor_state_assoc[] = { { "Wsem", STATES_WAITING_FOR_SEMAPHORE, 0 }, { "Wsig", STATES_WAITING_FOR_SIGNAL, 0 }, { "Wslmtx", STATES_WAITING_FOR_SYS_LOCK_MUTEX, 0 }, + { "Wslsem", STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE, 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 3c117bb..3223470 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -348,6 +348,7 @@ 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/semaphore.c libscore_a_SOURCES += src/smpbarrierwait.c libscore_a_SOURCES += src/kern_tc.c diff --git a/cpukit/score/include/rtems/score/statesimpl.h b/cpukit/score/include/rtems/score/statesimpl.h index 4ad8786..7805ca4 100644 --- a/cpukit/score/include/rtems/score/statesimpl.h +++ b/cpukit/score/include/rtems/score/statesimpl.h @@ -88,6 +88,8 @@ extern "C" { #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 waiting for a <sys/lock.h> semaphore. */ +#define STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE 0x4000000 /** This macro corresponds to a task which is in an interruptible * blocking state. @@ -106,6 +108,7 @@ extern "C" { STATES_WAITING_FOR_BARRIER | \ STATES_WAITING_FOR_BSD_WAKEUP | \ STATES_WAITING_FOR_SYS_LOCK_MUTEX | \ + STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE | \ STATES_WAITING_FOR_RWLOCK ) /** This macro corresponds to a task waiting which is blocked. */ diff --git a/cpukit/score/src/semaphore.c b/cpukit/score/src/semaphore.c new file mode 100644 index 0000000..acf50b8 --- /dev/null +++ b/cpukit/score/src/semaphore.c @@ -0,0 +1,118 @@ +/* + * 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 + +#define SEMAPHORE_TQ_OPERATIONS &_Thread_queue_Operations_priority + +static Thread_queue_Queue *_Semaphore_Get_thread_queue( + struct _Semaphore_Control *sem +) +{ + return (Thread_queue_Queue *) &sem->_Queue; +} + +static Thread_Control *_Semaphore_Queue_acquire( + struct _Semaphore_Control *sem, + ISR_lock_Context *lock_context +) +{ + Thread_Control *executing; + + _ISR_lock_ISR_disable( lock_context ); + executing = _Thread_Executing; + _Thread_queue_Queue_acquire_critical( + _Semaphore_Get_thread_queue( sem ), + &executing->Potpourri_stats, + lock_context + ); + + return executing; +} + +static void _Semaphore_Queue_release( + struct _Semaphore_Control *sem, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Queue_release( + _Semaphore_Get_thread_queue( sem ), + lock_context + ); +} + +void _Semaphore_Wait( struct _Semaphore_Control *sem ) +{ + ISR_lock_Context lock_context; + Thread_Control *executing; + unsigned int count; + + executing = _Semaphore_Queue_acquire( sem, &lock_context ); + + count = sem->_count; + if ( count > 0 ) { + sem->_count = count - 1; + _Semaphore_Queue_release( sem, &lock_context ); + } else { + _Thread_queue_Enqueue_critical( + _Semaphore_Get_thread_queue( sem ), + SEMAPHORE_TQ_OPERATIONS, + executing, + STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE, + 0, + 0, + &lock_context + ); + } +} + +void _Semaphore_Post( struct _Semaphore_Control *sem ) +{ + ISR_lock_Context lock_context; + Thread_queue_Heads *heads; + + _Semaphore_Queue_acquire( sem, &lock_context ); + + heads = _Semaphore_Get_thread_queue( sem )->heads; + if ( heads == NULL ) { + _Assert( sem->_count < UINT_MAX ); + ++sem->_count; + _Semaphore_Queue_release( sem, &lock_context ); + } else { + const Thread_queue_Operations *operations; + Thread_Control *first; + + operations = SEMAPHORE_TQ_OPERATIONS; + first = ( *operations->first )( heads ); + + _Thread_queue_Extract_critical( + _Semaphore_Get_thread_queue( sem ), + operations, + first, + &lock_context + ); + } +} + +#endif /* HAVE_STRUCT__THREAD_QUEUE_QUEUE */ diff --git a/testsuites/sptests/spsyslock01/init.c b/testsuites/sptests/spsyslock01/init.c index 7d93676..f6a2d3f 100644 --- a/testsuites/sptests/spsyslock01/init.c +++ b/testsuites/sptests/spsyslock01/init.c @@ -37,12 +37,15 @@ const char rtems_test_name[] = "SPSYSLOCK 1"; #define EVENT_REC_MTX_PRIO_INV RTEMS_EVENT_6 +#define EVENT_SEM_WAIT RTEMS_EVENT_7 + typedef struct { rtems_id high; rtems_id mid; rtems_id low; struct _Mutex_Control mtx; struct _Mutex_recursive_Control rec_mtx; + struct _Semaphore_Control sem; bool flag; } test_context; @@ -60,15 +63,19 @@ static void test_initialization(test_context *ctx) { struct _Mutex_Control mtx = _MUTEX_INITIALIZER; struct _Mutex_recursive_Control rec_mtx = _MUTEX_RECURSIVE_INITIALIZER; + struct _Semaphore_Control sem = _SEMAPHORE_INITIALIZER(1); _Mutex_Initialize(&ctx->mtx); _Mutex_recursive_Initialize(&ctx->rec_mtx); + _Semaphore_Initialize(&ctx->sem, 1); rtems_test_assert(memcmp(&mtx, &ctx->mtx, sizeof(mtx)) == 0); rtems_test_assert(memcmp(&rec_mtx, &ctx->rec_mtx, sizeof(rec_mtx)) == 0); + rtems_test_assert(memcmp(&sem, &ctx->sem, sizeof(sem)) == 0); _Mutex_Destroy(&mtx); _Mutex_recursive_Destroy(&rec_mtx); + _Semaphore_Destroy(&sem); } static void test_recursive_acquire_normal(test_context *ctx) @@ -153,6 +160,19 @@ static void test_prio_inv_recursive(test_context *ctx) rtems_test_assert(ctx->flag); } +static void test_sem(test_context *ctx) +{ + struct _Semaphore_Control *sem = &ctx->sem; + + _Semaphore_Wait(sem); + ctx->flag = false; + send_events(ctx, EVENT_SEM_WAIT); + rtems_test_assert(!ctx->flag); + _Semaphore_Post(sem); + rtems_test_assert(ctx->flag); + _Semaphore_Post(sem); +} + static void mid_task(rtems_task_argument arg) { rtems_test_assert(0); @@ -226,6 +246,11 @@ static void high_task(rtems_task_argument arg) sc = rtems_task_suspend(ctx->mid); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } + + if ((events & EVENT_SEM_WAIT) != 0) { + _Semaphore_Wait(&ctx->sem); + ctx->flag = true; + } } } @@ -265,6 +290,7 @@ static void test(void) test_recursive_acquire_recursive(ctx); test_prio_inv_normal(ctx); test_prio_inv_recursive(ctx); + test_sem(ctx); send_events(ctx, EVENT_MTX_DEADLOCK); diff --git a/testsuites/sptests/spsyslock01/spsyslock01.doc b/testsuites/sptests/spsyslock01/spsyslock01.doc index 440759d..1a7384c 100644 --- a/testsuites/sptests/spsyslock01/spsyslock01.doc +++ b/testsuites/sptests/spsyslock01/spsyslock01.doc @@ -14,7 +14,12 @@ directives: - _Mutex_recursive_Try_acquire() - _Mutex_recursive_Release() - _Mutex_recursive_Destroy() + - _Semaphore_Initialize() + - _Semaphore_Wait() + - _Semaphore_Post() + - _Semaphore_Destroy() concepts: - Ensure that self-contained mutexes and recursive mutexes work. + - Ensure that self-contained semaphores work. -- 1.8.4.5 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel