From 7237b3e0765f1e1e7516cf66986b3f204e0f4c88 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 2 Jul 2015 13:12:38 +0200 Subject: score: Add self-contained semaphore implementation --- 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 | 141 +++++++++++++++++++++++++ testsuites/sptests/spsyslock01/init.c | 60 +++++++++++ testsuites/sptests/spsyslock01/spsyslock01.doc | 5 + 6 files changed, 211 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 ae7f75d350..4656ed297a 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 c107805a3d..4b4c1f5fce 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -349,6 +349,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 4ad8786387..7805ca4c9b 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 mutex. */ #define STATES_WAITING_FOR_SYS_LOCK_MUTEX 0x2000000 +/** This macro corresponds to a task waiting for a 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 0000000000..94e5209fad --- /dev/null +++ b/cpukit/score/src/semaphore.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 + +#if HAVE_STRUCT__THREAD_QUEUE_QUEUE + +#include + +#include +#include +#include + +#define SEMAPHORE_TQ_OPERATIONS &_Thread_queue_Operations_priority + +typedef struct { + Thread_queue_Syslock_queue Queue; + unsigned int count; +} Semaphore_Control; + +RTEMS_STATIC_ASSERT( + offsetof( Semaphore_Control, Queue ) + == offsetof( struct _Semaphore_Control, _Queue ), + SEMAPHORE_CONTROL_QUEUE +); + +RTEMS_STATIC_ASSERT( + offsetof( Semaphore_Control, count ) + == offsetof( struct _Semaphore_Control, _count ), + SEMAPHORE_CONTROL_COUNT +); + +RTEMS_STATIC_ASSERT( + sizeof( Semaphore_Control ) == sizeof( struct _Semaphore_Control ), + SEMAPHORE_CONTROL_SIZE +); + +static Semaphore_Control *_Semaphore_Get( + struct _Semaphore_Control *_sem +) +{ + return (Semaphore_Control *) _sem; +} + +static Thread_Control *_Semaphore_Queue_acquire( + 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( + &sem->Queue.Queue, + &executing->Potpourri_stats, + lock_context + ); + + return executing; +} + +static void _Semaphore_Queue_release( + Semaphore_Control *sem, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Queue_release( &sem->Queue.Queue, lock_context ); +} + +void _Semaphore_Wait( struct _Semaphore_Control *_sem ) +{ + Semaphore_Control *sem ; + ISR_lock_Context lock_context; + Thread_Control *executing; + unsigned int count; + + sem = _Semaphore_Get( _sem ); + 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( + &sem->Queue.Queue, + SEMAPHORE_TQ_OPERATIONS, + executing, + STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE, + 0, + 0, + &lock_context + ); + } +} + +void _Semaphore_Post( struct _Semaphore_Control *_sem ) +{ + Semaphore_Control *sem; + ISR_lock_Context lock_context; + Thread_queue_Heads *heads; + + sem = _Semaphore_Get( _sem ); + _Semaphore_Queue_acquire( sem, &lock_context ); + + heads = sem->Queue.Queue.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( + &sem->Queue.Queue, + 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 5c060898e6..ece5943492 100644 --- a/testsuites/sptests/spsyslock01/init.c +++ b/testsuites/sptests/spsyslock01/init.c @@ -40,12 +40,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[2]; rtems_id mid; rtems_id low; struct _Mutex_Control mtx; struct _Mutex_recursive_Control rec_mtx; + struct _Semaphore_Control sem; int generation[2]; int current_generation[2]; } test_context; @@ -83,15 +86,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) @@ -269,6 +276,51 @@ static void test_mtx_timeout_recursive(test_context *ctx) send_event(ctx, idx, EVENT_REC_MTX_RELEASE); } +static void test_sem(test_context *ctx) +{ + struct _Semaphore_Control *sem = &ctx->sem; + size_t idx = 0; + int gen; + + _Semaphore_Wait(sem); + gen = ctx->generation[idx]; + send_event(ctx, idx, EVENT_SEM_WAIT); + rtems_test_assert(ctx->generation[idx] == gen); + _Semaphore_Post(sem); + rtems_test_assert(ctx->generation[idx] == gen + 1); + _Semaphore_Post(sem); +} + +static void test_sem_prio_wait_order(test_context *ctx) +{ + struct _Semaphore_Control *sem = &ctx->sem; + size_t a = 0; + size_t b = 1; + int gen_a; + int gen_b; + + _Semaphore_Wait(sem); + + gen_a = ctx->generation[a]; + gen_b = ctx->generation[b]; + + send_event(ctx, b, EVENT_SEM_WAIT); + send_event(ctx, a, EVENT_SEM_WAIT); + + rtems_test_assert(ctx->generation[a] == gen_a); + rtems_test_assert(ctx->generation[b] == gen_b); + + _Semaphore_Post(sem); + + rtems_test_assert(ctx->generation[a] == gen_a + 1); + rtems_test_assert(ctx->generation[b] == gen_b); + + _Semaphore_Post(sem); + + rtems_test_assert(ctx->generation[a] == gen_a + 1); + rtems_test_assert(ctx->generation[b] == gen_b + 1); +} + static void mid_task(rtems_task_argument arg) { rtems_test_assert(0); @@ -345,6 +397,11 @@ static void high_task(rtems_task_argument idx) sc = rtems_task_suspend(ctx->mid); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } + + if ((events & EVENT_SEM_WAIT) != 0) { + _Semaphore_Wait(&ctx->sem); + ctx->generation[idx] = generation(ctx, idx); + } } } @@ -400,11 +457,14 @@ static void test(void) test_prio_inv_recursive(ctx); test_mtx_timeout_normal(ctx); test_mtx_timeout_recursive(ctx); + test_sem(ctx); + test_sem_prio_wait_order(ctx); send_event(ctx, 0, EVENT_MTX_DEADLOCK); _Mutex_Destroy(&ctx->mtx); _Mutex_recursive_Destroy(&ctx->rec_mtx); + _Semaphore_Destroy(&ctx->sem); } static void Init(rtems_task_argument arg) diff --git a/testsuites/sptests/spsyslock01/spsyslock01.doc b/testsuites/sptests/spsyslock01/spsyslock01.doc index 440759d930..1a7384ce7e 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. -- cgit v1.2.3