From be43b79fcabb7551677e2d27c75e2a500e2ba622 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 22 Sep 2014 13:42:26 +0200 Subject: Replace RTEMS objects with custom implementation Performance analysis revealed that the standard RTEMS objects are a major bottleneck. The object get mechanism and attribute checks at runtime have a significant overhead. Use a custom implementation for synchronization primitives. This drops also the size of the synchronization primitives considerably. --- Makefile | 24 ++ freebsd-to-rtems.py | 2 + freebsd/sys/sys/_lock.h | 10 +- freebsd/sys/sys/_mutex.h | 5 + freebsd/sys/sys/_rwlock.h | 7 + freebsd/sys/sys/_sx.h | 5 + freebsd/sys/sys/condvar.h | 11 +- rtemsbsd/include/machine/rtems-bsd-mutex.h | 60 +++ rtemsbsd/include/machine/rtems-bsd-muteximpl.h | 220 +++++++++++ rtemsbsd/include/machine/rtems-bsd-support.h | 14 - rtemsbsd/rtems/rtems-bsd-condvar.c | 120 +++--- rtemsbsd/rtems/rtems-bsd-mutex.c | 108 +---- rtemsbsd/rtems/rtems-bsd-rwlock.c | 70 +--- rtemsbsd/rtems/rtems-bsd-shell.c | 69 +--- rtemsbsd/rtems/rtems-bsd-sx.c | 102 +---- testsuite/condvar01/test_main.c | 396 +++++++++++++++++++ testsuite/mutex01/test_main.c | 520 +++++++++++++++++++++++++ testsuite/rwlock01/test_main.c | 6 - 18 files changed, 1335 insertions(+), 414 deletions(-) create mode 100644 rtemsbsd/include/machine/rtems-bsd-mutex.h create mode 100644 rtemsbsd/include/machine/rtems-bsd-muteximpl.h create mode 100644 testsuite/condvar01/test_main.c create mode 100644 testsuite/mutex01/test_main.c diff --git a/Makefile b/Makefile index 9a11ef17..d3c663c5 100644 --- a/Makefile +++ b/Makefile @@ -1316,6 +1316,30 @@ TESTS += $(TEST_THREAD01) O_FILES += $(TEST_THREAD01_O_FILES) D_FILES += $(TEST_THREAD01_D_FILES) RUN_TESTS += $(TEST_THREAD01) + +TEST_MUTEX01 = testsuite/mutex01/mutex01.exe +TEST_MUTEX01_O_FILES = +TEST_MUTEX01_D_FILES = +TEST_MUTEX01_O_FILES += testsuite/mutex01/test_main.o +TEST_MUTEX01_D_FILES += testsuite/mutex01/test_main.d +$(TEST_MUTEX01): $(TEST_MUTEX01_O_FILES) $(LIB) + $(LINK.c) -Wl,-Map,testsuite/mutex01/mutex01.map $^ -lm -lz -o $@ +TESTS += $(TEST_MUTEX01) +O_FILES += $(TEST_MUTEX01_O_FILES) +D_FILES += $(TEST_MUTEX01_D_FILES) +RUN_TESTS += $(TEST_MUTEX01) + +TEST_CONDVAR01 = testsuite/condvar01/condvar01.exe +TEST_CONDVAR01_O_FILES = +TEST_CONDVAR01_D_FILES = +TEST_CONDVAR01_O_FILES += testsuite/condvar01/test_main.o +TEST_CONDVAR01_D_FILES += testsuite/condvar01/test_main.d +$(TEST_CONDVAR01): $(TEST_CONDVAR01_O_FILES) $(LIB) + $(LINK.c) -Wl,-Map,testsuite/condvar01/condvar01.map $^ -lm -lz -o $@ +TESTS += $(TEST_CONDVAR01) +O_FILES += $(TEST_CONDVAR01_O_FILES) +D_FILES += $(TEST_CONDVAR01_D_FILES) +RUN_TESTS += $(TEST_CONDVAR01) LIB_C_FILES += dhcpcd/arp.c dhcpcd/arp.o: dhcpcd/arp.c $(CC) $(CPPFLAGS) $(CFLAGS) -D__FreeBSD__ -DTHERE_IS_NO_FORK -DMASTER_ONLY -DINET -DINET6 -c $< -o $@ diff --git a/freebsd-to-rtems.py b/freebsd-to-rtems.py index 695a3d21..947bebac 100755 --- a/freebsd-to-rtems.py +++ b/freebsd-to-rtems.py @@ -2473,6 +2473,8 @@ tests.addTest('swi01', ['init', 'swi_test']) tests.addTest('timeout01', ['init', 'timeout_test']) tests.addTest('init01', ['test_main']) tests.addTest('thread01', ['test_main']) +tests.addTest('mutex01', ['test_main']) +tests.addTest('condvar01', ['test_main']) dhcpcd = Module('dhcpcd') dhcpcd.addSourceFiles( diff --git a/freebsd/sys/sys/_lock.h b/freebsd/sys/sys/_lock.h index 457ffd4d..35decd76 100644 --- a/freebsd/sys/sys/_lock.h +++ b/freebsd/sys/sys/_lock.h @@ -31,19 +31,11 @@ #ifndef _SYS__LOCK_H_ #define _SYS__LOCK_H_ -#ifdef __rtems__ -#include -#include -#endif struct lock_object { -#ifdef __rtems__ - rtems_chain_node lo_node; - rtems_id lo_id; -#endif /* __rtems__ */ const char *lo_name; /* Individual lock name. */ u_int lo_flags; - u_int lo_data; /* General class specific data. */ #ifndef __rtems__ + u_int lo_data; /* General class specific data. */ struct witness *lo_witness; /* Data for witness. */ #endif /* __rtems__ */ }; diff --git a/freebsd/sys/sys/_mutex.h b/freebsd/sys/sys/_mutex.h index 9bf2d39f..2f4a674e 100644 --- a/freebsd/sys/sys/_mutex.h +++ b/freebsd/sys/sys/_mutex.h @@ -30,6 +30,9 @@ #ifndef _SYS__MUTEX_H_ #define _SYS__MUTEX_H_ +#ifdef __rtems__ +#include +#endif /* __rtems__ */ /* * Sleep/spin mutex. @@ -38,6 +41,8 @@ struct mtx { struct lock_object lock_object; /* Common lock properties. */ #ifndef __rtems__ volatile uintptr_t mtx_lock; /* Owner and flags. */ +#else /* __rtems__ */ + rtems_bsd_mutex mutex; #endif /* __rtems__ */ }; diff --git a/freebsd/sys/sys/_rwlock.h b/freebsd/sys/sys/_rwlock.h index c5adac0e..25eb55e9 100644 --- a/freebsd/sys/sys/_rwlock.h +++ b/freebsd/sys/sys/_rwlock.h @@ -31,13 +31,20 @@ #ifndef _SYS__RWLOCK_H_ #define _SYS__RWLOCK_H_ +#ifdef __rtems__ +#include +#endif /* __rtems__ */ /* * Reader/writer lock. */ struct rwlock { struct lock_object lock_object; +#ifndef __rtems__ volatile uintptr_t rw_lock; +#else /* __rtems__ */ + rtems_bsd_mutex mutex; +#endif /* __rtems__ */ }; #endif /* !_SYS__RWLOCK_H_ */ diff --git a/freebsd/sys/sys/_sx.h b/freebsd/sys/sys/_sx.h index 699316b6..b07ac47a 100644 --- a/freebsd/sys/sys/_sx.h +++ b/freebsd/sys/sys/_sx.h @@ -30,6 +30,9 @@ #ifndef _SYS__SX_H_ #define _SYS__SX_H_ +#ifdef __rtems__ +#include +#endif /* __rtems__ */ /* * Shared/exclusive lock main structure definition. @@ -38,6 +41,8 @@ struct sx { struct lock_object lock_object; #ifndef __rtems__ volatile uintptr_t sx_lock; +#else /* __rtems__ */ + rtems_bsd_mutex mutex; #endif /* __rtems__ */ }; diff --git a/freebsd/sys/sys/condvar.h b/freebsd/sys/sys/condvar.h index 51da8170..8b2ee4db 100644 --- a/freebsd/sys/sys/condvar.h +++ b/freebsd/sys/sys/condvar.h @@ -44,17 +44,14 @@ TAILQ_HEAD(cv_waitq, thread); * optimization to avoid looking up the sleep queue if there are no waiters. */ #ifdef __rtems__ -#include -#include -#endif -struct cv { -#ifdef __rtems__ - rtems_chain_node cv_node; - pthread_cond_t cv_id; +#include #endif /* __rtems__ */ +struct cv { const char *cv_description; #ifndef __rtems__ int cv_waiters; +#else /* __rtems__ */ + Thread_queue_Control cv_waiters; #endif /* __rtems__ */ }; diff --git a/rtemsbsd/include/machine/rtems-bsd-mutex.h b/rtemsbsd/include/machine/rtems-bsd-mutex.h new file mode 100644 index 00000000..58b16f2c --- /dev/null +++ b/rtemsbsd/include/machine/rtems-bsd-mutex.h @@ -0,0 +1,60 @@ +/** + * @file + * + * @ingroup rtems_bsd_machine + * + * @brief TODO. + */ + +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEX_H_ +#define _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEX_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + Thread_Control *owner; + int nest_level; + RBTree_Control rivals; +} rtems_bsd_mutex; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEX_H_ */ diff --git a/rtemsbsd/include/machine/rtems-bsd-muteximpl.h b/rtemsbsd/include/machine/rtems-bsd-muteximpl.h new file mode 100644 index 00000000..69b42eb6 --- /dev/null +++ b/rtemsbsd/include/machine/rtems-bsd-muteximpl.h @@ -0,0 +1,220 @@ +/** + * @file + * + * @ingroup rtems_bsd_machine + * + * @brief Implementation of a mutex with a simple priority inheritance + * protocol. + */ + +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEXIMPL_H_ +#define _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEXIMPL_H_ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +static inline void +rtems_bsd_mutex_init(struct lock_object *lock, rtems_bsd_mutex *m, + struct lock_class *class, const char *name, const char *type, int flags) +{ + m->owner = NULL; + m->nest_level = 0; + _RBTree_Initialize_empty(&m->rivals); + + lock_init(lock, class, name, type, flags); +} + +static inline void +rtems_bsd_mutex_lock(struct lock_object *lock, rtems_bsd_mutex *m) +{ + ISR_Level level; + Thread_Control *executing; + Thread_Control *owner; + + _ISR_Disable(level); + + owner = m->owner; + executing = _Thread_Executing; + + if (owner == NULL) { + m->owner = executing; + ++executing->resource_count; + + _ISR_Enable(level); + } else if (owner == executing) { + BSD_ASSERT(lock->lo_flags & LO_RECURSABLE); + ++m->nest_level; + + _ISR_Enable(level); + } else { + _RBTree_Insert(&m->rivals, &executing->RBNode, + _Thread_queue_Compare_priority, false); + ++executing->resource_count; + + _Thread_Disable_dispatch(); + _ISR_Enable(level); + + _Scheduler_Change_priority_if_higher(_Scheduler_Get(owner), + owner, executing->current_priority, false); + _Thread_Set_state(executing, STATES_WAITING_FOR_MUTEX); + + _Thread_Enable_dispatch(); + } +} + +static inline int +rtems_bsd_mutex_trylock(struct lock_object *lock, rtems_bsd_mutex *m) +{ + int success; + ISR_Level level; + Thread_Control *executing; + Thread_Control *owner; + + _ISR_Disable(level); + + owner = m->owner; + executing = _Thread_Executing; + + if (owner == NULL) { + m->owner = executing; + ++executing->resource_count; + success = 1; + } else if (owner == executing) { + BSD_ASSERT(lock->lo_flags & LO_RECURSABLE); + ++m->nest_level; + success = 1; + } else { + success = 0; + } + + _ISR_Enable(level); + + return (success); +} + +static inline void +rtems_bsd_mutex_unlock(rtems_bsd_mutex *m) +{ + ISR_Level level; + int nest_level; + + _ISR_Disable(level); + + nest_level = m->nest_level; + if (nest_level != 0) { + m->nest_level = nest_level - 1; + + _ISR_Enable(level); + } else { + RBTree_Node *first; + Thread_Control *owner = m->owner; + + BSD_ASSERT(owner == _Thread_Executing); + --owner->resource_count; + + first = _RBTree_Get(&m->rivals, RBT_LEFT); + + if (first == NULL) { + m->owner = NULL; + + _ISR_Enable(level); + } else { + Thread_Control *new_owner = + THREAD_RBTREE_NODE_TO_THREAD(first); + + m->owner = new_owner; + + _Thread_Disable_dispatch(); + _ISR_Enable(level); + + _Thread_Clear_state(new_owner, STATES_WAITING_FOR_MUTEX); + + _Thread_Enable_dispatch(); + } + + if (!_Thread_Owns_resources(owner) + && owner->real_priority != owner->current_priority) { + _Thread_Disable_dispatch(); + _Thread_Change_priority(owner, owner->real_priority, true); + _Thread_Enable_dispatch(); + } + } +} + +static inline int +rtems_bsd_mutex_owned(rtems_bsd_mutex *m) +{ + + return (m->owner == _Thread_Get_executing()); +} + +static inline int +rtems_bsd_mutex_recursed(rtems_bsd_mutex *m) +{ + + return (m->nest_level); +} + +static inline void +rtems_bsd_mutex_destroy(struct lock_object *lock, rtems_bsd_mutex *m) +{ + BSD_ASSERT(_RBTree_Is_empty(&m->rivals)); + + if (rtems_bsd_mutex_owned(m)) { + m->nest_level = 0; + rtems_bsd_mutex_unlock(m); + } + + lock_destroy(lock); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEXIMPL_H_ */ diff --git a/rtemsbsd/include/machine/rtems-bsd-support.h b/rtemsbsd/include/machine/rtems-bsd-support.h index de148921..49d396f2 100644 --- a/rtemsbsd/include/machine/rtems-bsd-support.h +++ b/rtemsbsd/include/machine/rtems-bsd-support.h @@ -42,8 +42,6 @@ #include -#include - /* Debug */ #define BSD_PRINTF(fmt, ...) printf("%s: " fmt, __func__, ##__VA_ARGS__) @@ -54,16 +52,4 @@ #define BSD_ASSERT_RV(rv) BSD_ASSERT((rv) == 0) -extern rtems_chain_control rtems_bsd_lock_chain; - -extern rtems_chain_control rtems_bsd_mtx_chain; - -extern rtems_chain_control rtems_bsd_sx_chain; - -extern rtems_chain_control rtems_bsd_condvar_chain; - -extern rtems_chain_control rtems_bsd_callout_chain; - -extern rtems_chain_control rtems_bsd_malloc_chain; - #endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_SUPPORT_H_ */ diff --git a/rtemsbsd/rtems/rtems-bsd-condvar.c b/rtemsbsd/rtems/rtems-bsd-condvar.c index e64b4703..ff2f9c30 100644 --- a/rtemsbsd/rtems/rtems-bsd-condvar.c +++ b/rtemsbsd/rtems/rtems-bsd-condvar.c @@ -39,153 +39,127 @@ #include #include -#include #include +#include #include -#include #include #include #include #include -#include #include - -RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_condvar_chain); +#include void cv_init(struct cv *cv, const char *desc) { - int rv = pthread_cond_init(&cv->cv_id, NULL); - - BSD_ASSERT_RV(rv); cv->cv_description = desc; - - rtems_chain_append(&rtems_bsd_condvar_chain, &cv->cv_node); + _Thread_queue_Initialize(&cv->cv_waiters, THREAD_QUEUE_DISCIPLINE_PRIORITY, + STATES_WAITING_FOR_CONDITION_VARIABLE, EWOULDBLOCK); } void cv_destroy(struct cv *cv) { - int rv = pthread_cond_destroy(&cv->cv_id); - BSD_ASSERT_RV(rv); - - rtems_chain_extract(&cv->cv_node); + BSD_ASSERT(_Thread_queue_First(&cv->cv_waiters) == NULL); } -static int _cv_wait_support(struct cv *cv, struct lock_object *lock, int timo, bool relock) +static int +_cv_wait_support(struct cv *cv, struct lock_object *lock, Watchdog_Interval timo, bool relock) { - int eno = 0; - Objects_Locations location = OBJECTS_ERROR; - POSIX_Condition_variables_Control *pcv = _POSIX_Condition_variables_Get(&cv->cv_id, &location); - - if (location == OBJECTS_LOCAL) { - struct lock_class *class = LOCK_CLASS(lock); - int lock_state; - - if (pcv->Mutex != POSIX_CONDITION_VARIABLES_NO_MUTEX && pcv->Mutex != lock->lo_id) { - _Thread_Enable_dispatch(); - - BSD_ASSERT(false); - - return EINVAL; - } + int error; + struct lock_class *class; + int lock_state; + Thread_Control *executing; - lock_state = (*class->lc_unlock)(lock); + _Thread_Disable_dispatch(); - pcv->Mutex = lock->lo_id; + class = LOCK_CLASS(lock); + lock_state = (*class->lc_unlock)(lock); - _Thread_queue_Enter_critical_section(&pcv->Wait_queue); - _Thread_Executing->Wait.return_code = 0; - _Thread_Executing->Wait.queue = &pcv->Wait_queue; - _Thread_Executing->Wait.id = cv->cv_id; + _Thread_queue_Enter_critical_section(&cv->cv_waiters); - /* FIXME: Integer conversion */ - _Thread_queue_Enqueue(&pcv->Wait_queue, _Thread_Executing, (Watchdog_Interval) timo); + executing = _Thread_Executing; + executing->Wait.return_code = 0; + executing->Wait.queue = &cv->cv_waiters; - DROP_GIANT(); + _Thread_queue_Enqueue(&cv->cv_waiters, executing, timo); - _Thread_Enable_dispatch(); + DROP_GIANT(); - PICKUP_GIANT(); + _Thread_Enable_dispatch(); - eno = (int) _Thread_Executing->Wait.return_code; - if (eno != 0) { - if (eno == ETIMEDOUT) { - eno = EWOULDBLOCK; - } else { - BSD_ASSERT(false); + PICKUP_GIANT(); - eno = EINVAL; - } - } + error = (int)executing->Wait.return_code; - if (relock) { - (*class->lc_lock)(lock, lock_state); - } - - return eno; + if (relock) { + (*class->lc_lock)(lock, lock_state); } - BSD_PANIC("unexpected object location"); + return (error); } void _cv_wait(struct cv *cv, struct lock_object *lock) { + _cv_wait_support(cv, lock, 0, true); } void _cv_wait_unlock(struct cv *cv, struct lock_object *lock) { + _cv_wait_support(cv, lock, 0, false); } int _cv_timedwait(struct cv *cv, struct lock_object *lock, int timo) { - if (timo <= 0) { + if (timo <= 0) timo = 1; - } - return _cv_wait_support(cv, lock, timo, true); + return (_cv_wait_support(cv, lock, (Watchdog_Interval)timo, true)); } void cv_signal(struct cv *cv) { - int rv = pthread_cond_signal(&cv->cv_id); - BSD_ASSERT_RV(rv); + _Thread_Disable_dispatch(); + _Thread_queue_Dequeue(&cv->cv_waiters); + _Thread_Enable_dispatch(); } void cv_broadcastpri(struct cv *cv, int pri) { - int rv = 0; - /* FIXME: What to do with "pri"? */ + _Thread_Disable_dispatch(); + + while (_Thread_queue_Dequeue(&cv->cv_waiters) != NULL) { + /* Again */ + } - rv = pthread_cond_broadcast(&cv->cv_id); - BSD_ASSERT_RV(rv); + _Thread_Enable_dispatch(); } + int -_cv_wait_sig(struct cv *cvp, struct lock_object *lock) +_cv_wait_sig(struct cv *cv, struct lock_object *lock) { - /* XXX */ - return _cv_wait_support(cvp, lock, 0, true); + + return (_cv_wait_support(cv, lock, 0, true)); } int -_cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo) +_cv_timedwait_sig(struct cv *cv, struct lock_object *lock, int timo) { - /* XXX */ - if (timo <= 0) { + + if (timo <= 0) timo = 1; - } - return _cv_wait_support(cvp, lock, timo, true); + return (_cv_wait_support(cv, lock, (Watchdog_Interval)timo, true)); } diff --git a/rtemsbsd/rtems/rtems-bsd-mutex.c b/rtemsbsd/rtems/rtems-bsd-mutex.c index b975b977..37cc04ca 100644 --- a/rtemsbsd/rtems/rtems-bsd-mutex.c +++ b/rtemsbsd/rtems/rtems-bsd-mutex.c @@ -38,12 +38,7 @@ */ #include -#include -#include - -#include -#include -#include +#include #include #include @@ -59,8 +54,6 @@ static int owner_mtx(struct lock_object *lock, struct thread **owner); #endif static int unlock_mtx(struct lock_object *lock); -RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_mtx_chain); - /* * Lock classes for sleep and spin mutexes. */ @@ -103,19 +96,15 @@ assert_mtx(struct lock_object *lock, int what) void lock_mtx(struct lock_object *lock, int how) { - - mtx_lock((struct mtx *)lock); + mtx_lock((struct mtx *)lock); } int unlock_mtx(struct lock_object *lock) { - struct mtx *m; + mtx_unlock((struct mtx *)lock); - m = (struct mtx *)lock; - mtx_assert(m, MA_OWNED | MA_NOTRECURSED); - mtx_unlock(m); - return (0); + return (0); } @@ -135,9 +124,6 @@ mtx_init(struct mtx *m, const char *name, const char *type, int opts) { struct lock_class *class; int flags; - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_id id = RTEMS_ID_NONE; - rtems_attribute attr = RTEMS_LOCAL | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY; /* Determine lock class and lock flags. */ if (opts & MTX_SPIN) @@ -148,55 +134,26 @@ mtx_init(struct mtx *m, const char *name, const char *type, int opts) if (opts & MTX_RECURSE) flags |= LO_RECURSABLE; - lock_init(&m->lock_object, class, name, type, flags); - - sc = rtems_semaphore_create( - rtems_build_name('_', 'M', 'T', 'X'), - 1, - attr, - BSD_TASK_PRIORITY_RESOURCE_OWNER, - &id - ); - BSD_ASSERT_SC(sc); - - m->lock_object.lo_id = id; - - rtems_chain_append(&rtems_bsd_mtx_chain, &m->lock_object.lo_node); + rtems_bsd_mutex_init(&m->lock_object, &m->mutex, class, name, type, + flags); } void _mtx_lock_flags(struct mtx *m, int opts, const char *file, int line) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_obtain(m->lock_object.lo_id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - BSD_ASSERT_SC(sc); + rtems_bsd_mutex_lock(&m->lock_object, &m->mutex); } int _mtx_trylock(struct mtx *m, int opts, const char *file, int line) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_obtain(m->lock_object.lo_id, RTEMS_NO_WAIT, 0); - if (sc == RTEMS_SUCCESSFUL) { - return 1; - } else if (sc == RTEMS_UNSATISFIED) { - return 0; - } else { - BSD_ASSERT_SC(sc); - - return 0; - } + return (rtems_bsd_mutex_trylock(&m->lock_object, &m->mutex)); } void _mtx_unlock_flags(struct mtx *m, int opts, const char *file, int line) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_release(m->lock_object.lo_id); - BSD_ASSERT_SC(sc); + rtems_bsd_mutex_unlock(&m->mutex); } /* @@ -238,38 +195,12 @@ _mtx_assert(struct mtx *m, int what, const char *file, int line) int mtx_owned(struct mtx *m) { - Objects_Locations location; - Semaphore_Control *sema = _Semaphore_Get(m->lock_object.lo_id, &location); - - if (location == OBJECTS_LOCAL && !_Attributes_Is_counting_semaphore(sema->attribute_set)) { - int owned = sema->Core_control.mutex.holder == _Thread_Executing; - - _Thread_Enable_dispatch(); - - return owned; - } else { - _Thread_Enable_dispatch(); - - BSD_PANIC("unexpected semaphore location or attributes"); - } + return (rtems_bsd_mutex_owned(&m->mutex)); } int mtx_recursed(struct mtx *m) { - Objects_Locations location; - Semaphore_Control *sema = _Semaphore_Get(m->lock_object.lo_id, &location); - - if (location == OBJECTS_LOCAL && !_Attributes_Is_counting_semaphore(sema->attribute_set)) { - int recursed = sema->Core_control.mutex.nest_count != 0; - - _Thread_Enable_dispatch(); - - return recursed; - } else { - _Thread_Enable_dispatch(); - - BSD_PANIC("unexpected semaphore location or attributes"); - } + return (rtems_bsd_mutex_recursed(&m->mutex)); } void @@ -283,23 +214,8 @@ mtx_sysinit(void *arg) void mtx_destroy(struct mtx *m) { - rtems_status_code sc; - - do { - sc = rtems_semaphore_delete(m->lock_object.lo_id); - if (sc == RTEMS_RESOURCE_IN_USE) { - BSD_ASSERT(mtx_owned(m)); - - mtx_unlock(m); - } else { - BSD_ASSERT_SC(sc); - } - } while (sc != RTEMS_SUCCESSFUL); - - rtems_chain_extract(&m->lock_object.lo_node); - m->lock_object.lo_id = 0; - m->lock_object.lo_flags &= ~LO_INITIALIZED; + rtems_bsd_mutex_destroy(&m->lock_object, &m->mutex); } void diff --git a/rtemsbsd/rtems/rtems-bsd-rwlock.c b/rtemsbsd/rtems/rtems-bsd-rwlock.c index b85f3742..b6540b54 100644 --- a/rtemsbsd/rtems/rtems-bsd-rwlock.c +++ b/rtemsbsd/rtems/rtems-bsd-rwlock.c @@ -46,17 +46,13 @@ */ #include -#include -#include - -#include +#include #include #include #include #include #include -#include #ifndef INVARIANTS #define _rw_assert(rw, what, file, line) @@ -83,8 +79,6 @@ struct lock_class lock_class_rw = { #endif }; -RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_rwlock_chain); - void assert_rw(struct lock_object *lock, int what) { @@ -94,29 +88,15 @@ assert_rw(struct lock_object *lock, int what) void lock_rw(struct lock_object *lock, int how) { - struct rwlock *rw; - - rw = (struct rwlock *)lock; - if (how) - rw_wlock(rw); - else - rw_rlock(rw); + rw_wlock((struct rwlock *)lock); } int unlock_rw(struct lock_object *lock) { - struct rwlock *rw; - - rw = (struct rwlock *)lock; - rw_assert(rw, RA_LOCKED | LA_NOTRECURSED); - if (rw->rw_lock & RW_LOCK_READ) { - rw_runlock(rw); - return (0); - } else { - rw_wunlock(rw); - return (1); - } + rw_unlock((struct rwlock *)lock); + + return (0); } #ifdef KDTRACE_HOOKS @@ -136,34 +116,20 @@ void rw_init_flags(struct rwlock *rw, const char *name, int opts) { int flags; - rtems_status_code sc; - rtems_id id; - rtems_attribute attr = RTEMS_LOCAL | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY; flags = LO_UPGRADABLE; if (opts & RW_RECURSE) flags |= LO_RECURSABLE; - lock_init(&rw->lock_object, &lock_class_rw, name, NULL, flags); - - sc = rtems_semaphore_create( - rtems_build_name('_', '_', 'R', 'W'), - 1, - attr, - BSD_TASK_PRIORITY_RESOURCE_OWNER, - &id - ); - BSD_ASSERT_SC(sc); - - rw->lock_object.lo_id = id; - - rtems_chain_append(&rtems_bsd_rwlock_chain, &rw->lock_object.lo_node); + rtems_bsd_mutex_init(&rw->lock_object, &rw->mutex, &lock_class_rw, + name, NULL, flags); } void rw_destroy(struct rwlock *rw) { - mtx_destroy((struct mtx *) rw); + + rtems_bsd_mutex_destroy(&rw->lock_object, &rw->mutex); } void @@ -185,55 +151,55 @@ rw_sysinit_flags(void *arg) int rw_wowned(struct rwlock *rw) { - return mtx_owned((struct mtx *) rw); + return (rtems_bsd_mutex_owned(&rw->mutex)); } void _rw_wlock(struct rwlock *rw, const char *file, int line) { - _mtx_lock_flags((struct mtx *) rw, 0, file, line); + rtems_bsd_mutex_lock(&rw->lock_object, &rw->mutex); } int _rw_try_wlock(struct rwlock *rw, const char *file, int line) { - return _mtx_trylock((struct mtx *) rw, 0, file, line); + return (rtems_bsd_mutex_trylock(&rw->lock_object, &rw->mutex)); } void _rw_wunlock(struct rwlock *rw, const char *file, int line) { - _mtx_unlock_flags((struct mtx *) rw, 0, file, line); + rtems_bsd_mutex_unlock(&rw->mutex); } void _rw_rlock(struct rwlock *rw, const char *file, int line) { - _mtx_lock_flags((struct mtx *) rw, 0, file, line); + rtems_bsd_mutex_lock(&rw->lock_object, &rw->mutex); } int _rw_try_rlock(struct rwlock *rw, const char *file, int line) { - return _mtx_trylock((struct mtx *) rw, 0, file, line); + return (rtems_bsd_mutex_trylock(&rw->lock_object, &rw->mutex)); } void _rw_runlock(struct rwlock *rw, const char *file, int line) { - _mtx_unlock_flags((struct mtx *) rw, 0, file, line); + rtems_bsd_mutex_unlock(&rw->mutex); } int _rw_try_upgrade(struct rwlock *rw, const char *file, int line) { - return 1; + return (1); } void _rw_downgrade(struct rwlock *rw, const char *file, int line) { - /* Nothing to do */ + /* Nothing to do */ } #ifdef INVARIANT_SUPPORT diff --git a/rtemsbsd/rtems/rtems-bsd-shell.c b/rtemsbsd/rtems/rtems-bsd-shell.c index 2fa1aaa3..7ccb170c 100644 --- a/rtemsbsd/rtems/rtems-bsd-shell.c +++ b/rtemsbsd/rtems/rtems-bsd-shell.c @@ -44,66 +44,11 @@ #include #include #include -#include -#include -#include -#include #include #include #include -static void -rtems_bsd_dump_mtx(void) -{ - rtems_chain_control *chain = &rtems_bsd_mtx_chain; - rtems_chain_node *node = rtems_chain_first(chain); - - printf("mtx dump:\n"); - - while (!rtems_chain_is_tail(chain, node)) { - struct lock_object *lo = (struct lock_object *) node; - - printf("\t%s: 0x%08x\n", lo->lo_name, lo->lo_id); - - node = rtems_chain_next(node); - } -} - -static void -rtems_bsd_dump_sx(void) -{ - rtems_chain_control *chain = &rtems_bsd_sx_chain; - rtems_chain_node *node = rtems_chain_first(chain); - - printf("sx dump:\n"); - - while (!rtems_chain_is_tail(chain, node)) { - struct lock_object *lo = (struct lock_object *) node; - - printf("\t%s: 0x%08x\n", lo->lo_name, lo->lo_id); - - node = rtems_chain_next(node); - } -} - -static void -rtems_bsd_dump_condvar(void) -{ - rtems_chain_control *chain = &rtems_bsd_condvar_chain; - rtems_chain_node *node = rtems_chain_first(chain); - - printf("condvar dump:\n"); - - while (!rtems_chain_is_tail(chain, node)) { - struct cv *cv = (struct cv *) node; - - printf("\t%s: 0x%08x\n", cv->cv_description, cv->cv_id); - - node = rtems_chain_next(node); - } -} - static void rtems_bsd_dump_thread(void) { @@ -122,7 +67,7 @@ rtems_bsd_dump_thread(void) } static const char rtems_bsd_usage [] = - "bsd {all|mtx|sx|condvar|thread|callout}"; + "bsd {all|condvar|thread|callout}"; #define CMP(s) all || strcasecmp(argv [1], s) == 0 @@ -138,18 +83,6 @@ rtems_bsd_info(int argc, char **argv) all = true; } - if (CMP("mtx")) { - rtems_bsd_dump_mtx(); - usage = false; - } - if (CMP("sx")) { - rtems_bsd_dump_sx(); - usage = false; - } - if (CMP("condvar")) { - rtems_bsd_dump_condvar(); - usage = false; - } if (CMP("thread")) { rtems_bsd_dump_thread(); usage = false; diff --git a/rtemsbsd/rtems/rtems-bsd-sx.c b/rtemsbsd/rtems/rtems-bsd-sx.c index 3d0e79e0..46ab2d17 100644 --- a/rtemsbsd/rtems/rtems-bsd-sx.c +++ b/rtemsbsd/rtems/rtems-bsd-sx.c @@ -38,11 +38,7 @@ */ #include -#include - -#include -#include -#include +#include #include #include @@ -75,8 +71,6 @@ struct lock_class lock_class_sx = { #endif }; -RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_sx_chain); - void assert_sx(struct lock_object *lock, int what) { @@ -86,29 +80,15 @@ assert_sx(struct lock_object *lock, int what) void lock_sx(struct lock_object *lock, int how) { - struct sx *sx; - - sx = (struct sx *)lock; - if (how) - sx_xlock(sx); - else - sx_slock(sx); + sx_xlock((struct sx *)lock); } int unlock_sx(struct lock_object *lock) { - struct sx *sx; + sx_xunlock((struct sx *)lock); - sx = (struct sx *)lock; - sx_assert(sx, SA_LOCKED | SA_NOTRECURSED); - if (sx_xlocked(sx)) { - sx_xunlock(sx); - return (1); - } else { - sx_sunlock(sx); - return (0); - } + return (0); } #ifdef KDTRACE_HOOKS @@ -136,89 +116,46 @@ void sx_init_flags(struct sx *sx, const char *description, int opts) { int flags; - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_id id = RTEMS_ID_NONE; - rtems_attribute attr = RTEMS_LOCAL | RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE; flags = LO_SLEEPABLE | LO_UPGRADABLE; if (opts & SX_RECURSE) flags |= LO_RECURSABLE; - lock_init(&sx->lock_object, &lock_class_sx, description, NULL, flags); - - sc = rtems_semaphore_create( - rtems_build_name( '_', 'S', 'X', ' '), - 1, - attr, - 0, - &id - ); - BSD_ASSERT_SC(sc); - - sx->lock_object.lo_id = id; - - rtems_chain_append(&rtems_bsd_sx_chain, &sx->lock_object.lo_node); + rtems_bsd_mutex_init(&sx->lock_object, &sx->mutex, &lock_class_sx, + description, NULL, flags); } void sx_destroy(struct sx *sx) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_delete( sx->lock_object.lo_id); - BSD_ASSERT_SC(sc); - - rtems_chain_extract(&sx->lock_object.lo_node); - sx->lock_object.lo_id = 0; - sx->lock_object.lo_flags &= ~LO_INITIALIZED; + rtems_bsd_mutex_destroy(&sx->lock_object, &sx->mutex); } int _sx_xlock(struct sx *sx, int opts, const char *file, int line) { - rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_bsd_mutex_lock(&sx->lock_object, &sx->mutex); - #warning "SX_INTERRUPTIBLE NOT SUPPORTED YET" - /* BSD_ASSERT((opts & SX_INTERRUPTIBLE) == 0); */ - BSD_ASSERT(!rtems_interrupt_is_in_progress()); - - sc = rtems_semaphore_obtain( sx->lock_object.lo_id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - BSD_ASSERT_SC(sc); - - return 0; + return (0); } int _sx_try_xlock(struct sx *sx, const char *file, int line) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_obtain( sx->lock_object.lo_id, RTEMS_NO_WAIT, 0); - if (sc == RTEMS_SUCCESSFUL) { - return 1; - } else if (sc == RTEMS_UNSATISFIED) { - return 0; - } else { - BSD_ASSERT_SC(sc); - - return 0; - } + return (rtems_bsd_mutex_trylock(&sx->lock_object, &sx->mutex)); } void _sx_xunlock(struct sx *sx, const char *file, int line) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_release( sx->lock_object.lo_id); - BSD_ASSERT_SC(sc); + rtems_bsd_mutex_unlock(&sx->mutex); } int _sx_try_upgrade(struct sx *sx, const char *file, int line) { - return 1; + return (1); } void @@ -322,18 +259,5 @@ _sx_assert(struct sx *sx, int what, const char *file, int line) int sx_xlocked(struct sx *sx) { - Objects_Locations location; - Semaphore_Control *sema = _Semaphore_Get(sx->lock_object.lo_id, &location); - - if (location == OBJECTS_LOCAL && !_Attributes_Is_counting_semaphore(sema->attribute_set)) { - int xlocked = sema->Core_control.mutex.holder == _Thread_Executing; - - _Thread_Enable_dispatch(); - - return xlocked; - } else { - _Thread_Enable_dispatch(); - - BSD_PANIC("unexpected semaphore location or attributes"); - } + return (rtems_bsd_mutex_owned(&sx->mutex)); } diff --git a/testsuite/condvar01/test_main.c b/testsuite/condvar01/test_main.c new file mode 100644 index 00000000..53c98152 --- /dev/null +++ b/testsuite/condvar01/test_main.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define TEST_NAME "LIBBSD CONDVAR 1" + +#define PRIO_MASTER 3 + +#define EVENT_LOCK RTEMS_EVENT_0 + +#define EVENT_UNLOCK RTEMS_EVENT_1 + +#define EVENT_WAIT RTEMS_EVENT_2 + +#define EVENT_WAIT_SIG RTEMS_EVENT_3 + +#define EVENT_WAIT_UNLOCK RTEMS_EVENT_4 + +#define EVENT_TIMEDWAIT RTEMS_EVENT_5 + +#define EVENT_TIMEDWAIT_SIG RTEMS_EVENT_6 + +#define WORKER_COUNT 2 + +typedef struct { + struct mtx mtx; + struct cv cv; + int rv; + int timo; + rtems_id worker_task[WORKER_COUNT]; + bool done[WORKER_COUNT]; +} test_context; + +static test_context test_instance; + +static const rtems_task_priority prio_worker[2] = { 2, 1 }; + +static void +set_self_prio(rtems_task_priority prio) +{ + rtems_status_code sc; + + sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void +worker_task(rtems_task_argument index) +{ + test_context *ctx = &test_instance; + struct mtx *mtx = &ctx->mtx; + struct cv *cv = &ctx->cv; + + while (true) { + rtems_status_code sc; + rtems_event_set events; + + sc = rtems_event_receive( + RTEMS_ALL_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + assert(sc == RTEMS_SUCCESSFUL); + + if ((events & EVENT_LOCK) != 0) { + mtx_lock(mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_UNLOCK) != 0) { + mtx_unlock(mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_WAIT) != 0) { + cv_wait(cv, mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_WAIT_SIG) != 0) { + int rv = cv_wait_sig(cv, mtx); + assert(rv == 0); + ctx->done[index] = true; + } + + if ((events & EVENT_WAIT_UNLOCK) != 0) { + cv_wait_unlock(cv, mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_TIMEDWAIT) != 0) { + ctx->rv = cv_timedwait(cv, mtx, ctx->timo); + ctx->done[index] = true; + } + + if ((events & EVENT_TIMEDWAIT_SIG) != 0) { + ctx->rv = cv_timedwait_sig(cv, mtx, ctx->timo); + ctx->done[index] = true; + } + } +} + +static void +send_events(test_context *ctx, rtems_event_set events, size_t index) +{ + rtems_status_code sc; + + sc = rtems_event_send(ctx->worker_task[index], events); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void +start_worker(test_context *ctx) +{ + size_t i; + + for (i = 0; i < WORKER_COUNT; ++i) { + rtems_status_code sc; + + sc = rtems_task_create( + rtems_build_name('W', 'O', 'R', 'K'), + prio_worker[i], + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_FLOATING_POINT, + &ctx->worker_task[i] + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start( + ctx->worker_task[i], + worker_task, + i + ); + assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void +delete_worker(test_context *ctx) +{ + size_t i; + + for (i = 0; i < WORKER_COUNT; ++i) { + rtems_status_code sc; + + sc = rtems_task_delete(ctx->worker_task[i]); + assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void +test_cv_wait_signal(test_context *ctx, rtems_event_set event, const char *name) +{ + struct mtx *mtx = &ctx->mtx; + struct cv *cv = &ctx->cv; + size_t low = 0; + size_t high = 1; + + printf("test cv %s signal\n", name); + + mtx_lock(mtx); + mtx_unlock(mtx); + + ctx->timo = 0; + + ctx->done[low] = false; + send_events(ctx, EVENT_LOCK, low); + assert(ctx->done[low]); + + ctx->done[high] = false; + send_events(ctx, EVENT_LOCK, high); + assert(!ctx->done[high]); + + ctx->done[low] = false; + send_events(ctx, event, low); + assert(!ctx->done[low]); + assert(ctx->done[high]); + + ctx->done[low] = false; + ctx->done[high] = false; + send_events(ctx, event, high); + assert(!ctx->done[low]); + assert(!ctx->done[high]); + + cv_signal(cv); + assert(!ctx->done[low]); + assert(ctx->done[high]); + + if (event != EVENT_WAIT_UNLOCK) { + cv_signal(cv); + assert(!ctx->done[low]); + + ctx->done[high] = false; + send_events(ctx, EVENT_UNLOCK, high); + assert(ctx->done[high]); + assert(ctx->done[low]); + + ctx->done[low] = false; + send_events(ctx, EVENT_UNLOCK, low); + assert(ctx->done[low]); + } else { + cv_signal(cv); + assert(ctx->done[low]); + } + + mtx_lock(mtx); + mtx_unlock(mtx); +} + +static void +test_cv_wait_broadcast(test_context *ctx, rtems_event_set event, const char *name) +{ + struct mtx *mtx = &ctx->mtx; + struct cv *cv = &ctx->cv; + size_t low = 0; + size_t high = 1; + + printf("test cv %s broadcast\n", name); + + mtx_lock(mtx); + mtx_unlock(mtx); + + ctx->timo = 0; + + ctx->done[low] = false; + send_events(ctx, EVENT_LOCK, low); + assert(ctx->done[low]); + + ctx->done[high] = false; + send_events(ctx, EVENT_LOCK, high); + assert(!ctx->done[high]); + + ctx->done[low] = false; + send_events(ctx, event, low); + assert(!ctx->done[low]); + assert(ctx->done[high]); + + ctx->done[low] = false; + ctx->done[high] = false; + send_events(ctx, event, high); + assert(!ctx->done[low]); + assert(!ctx->done[high]); + + if (event != EVENT_WAIT_UNLOCK) { + cv_broadcast(cv); + assert(!ctx->done[low]); + + ctx->done[high] = false; + send_events(ctx, EVENT_UNLOCK, high); + assert(ctx->done[high]); + assert(ctx->done[low]); + + ctx->done[low] = false; + send_events(ctx, EVENT_UNLOCK, low); + assert(ctx->done[low]); + } else { + cv_broadcast(cv); + assert(ctx->done[low]); + assert(ctx->done[high]); + } + + mtx_lock(mtx); + mtx_unlock(mtx); +} + +static void +test_cv_wait(test_context *ctx, rtems_event_set event, const char *name) +{ + test_cv_wait_signal(ctx, event, name); + test_cv_wait_broadcast(ctx, event, name); +} + +static void +test_cv_wait_timeout(test_context *ctx) +{ + size_t index = 0; + rtems_status_code sc; + + puts("test cv wait timeout"); + + ctx->timo = 2; + + ctx->done[index] = false; + send_events(ctx, EVENT_LOCK, index); + assert(ctx->done[index]); + + ctx->done[index] = false; + ctx->rv = 0; + send_events(ctx, EVENT_TIMEDWAIT, index); + assert(!ctx->done[index]); + + sc = rtems_task_wake_after(ctx->timo); + assert(sc == RTEMS_SUCCESSFUL); + assert(ctx->done[index]); + assert(ctx->rv == EWOULDBLOCK); + + ctx->done[index] = false; + ctx->rv = 0; + send_events(ctx, EVENT_TIMEDWAIT_SIG, index); + assert(!ctx->done[index]); + + sc = rtems_task_wake_after(ctx->timo); + assert(sc == RTEMS_SUCCESSFUL); + assert(ctx->done[index]); + assert(ctx->rv == EWOULDBLOCK); + + ctx->done[index] = false; + send_events(ctx, EVENT_UNLOCK, index); + assert(ctx->done[index]); +} + +static void +alloc_basic_resources(void) +{ + curthread; +} + +static void +test_main(void) +{ + test_context *ctx = &test_instance; + rtems_resource_snapshot snapshot; + + alloc_basic_resources(); + + rtems_resource_snapshot_take(&snapshot); + + cv_init(&ctx->cv, "test"); + assert(strcmp(cv_wmesg(&ctx->cv), "test") == 0); + + set_self_prio(PRIO_MASTER); + start_worker(ctx); + + test_cv_wait(ctx, EVENT_WAIT, "wait"); + test_cv_wait(ctx, EVENT_WAIT_SIG, "wait sig"); + test_cv_wait(ctx, EVENT_WAIT_UNLOCK, "wait unlock"); + test_cv_wait(ctx, EVENT_TIMEDWAIT, "timed wait"); + test_cv_wait(ctx, EVENT_TIMEDWAIT_SIG, "timed wait sig"); + + test_cv_wait_timeout(ctx); + + delete_worker(ctx); + cv_destroy(&ctx->cv); + + assert(rtems_resource_snapshot_check(&snapshot)); + + exit(0); +} + +#include diff --git a/testsuite/mutex01/test_main.c b/testsuite/mutex01/test_main.c new file mode 100644 index 00000000..504d80af --- /dev/null +++ b/testsuite/mutex01/test_main.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define TEST_NAME "LIBBSD MUTEX 1" + +#define PRIO_MASTER 3 + +#define EVENT_LOCK RTEMS_EVENT_0 + +#define EVENT_TRY_LOCK RTEMS_EVENT_1 + +#define EVENT_UNLOCK RTEMS_EVENT_2 + +#define EVENT_SLEEP RTEMS_EVENT_3 + +#define WORKER_COUNT 2 + +typedef struct { + struct mtx mtx; + struct mtx mtx2; + int rv; + int timo; + rtems_id worker_task[WORKER_COUNT]; + bool done[WORKER_COUNT]; +} test_context; + +static test_context test_instance; + +static const rtems_task_priority prio_worker[2] = { 2, 1 }; + +static void +set_self_prio(rtems_task_priority prio) +{ + rtems_status_code sc; + + sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio); + assert(sc == RTEMS_SUCCESSFUL); +} + +static rtems_task_priority +get_self_prio(void) +{ + rtems_status_code sc; + rtems_task_priority prio; + + sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &prio); + assert(sc == RTEMS_SUCCESSFUL); + + return prio; +} + +static void +worker_task(rtems_task_argument index) +{ + test_context *ctx = &test_instance; + struct mtx *mtx = &ctx->mtx; + + while (true) { + rtems_status_code sc; + rtems_event_set events; + + sc = rtems_event_receive( + RTEMS_ALL_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + assert(sc == RTEMS_SUCCESSFUL); + + if ((events & EVENT_LOCK) != 0) { + mtx_lock(mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_TRY_LOCK) != 0) { + ctx->rv = mtx_trylock(mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_UNLOCK) != 0) { + mtx_unlock(mtx); + ctx->done[index] = true; + } + + if ((events & EVENT_SLEEP) != 0) { + ctx->rv = mtx_sleep(ctx, mtx, 0, "worker", ctx->timo); + ctx->done[index] = true; + } + } +} + +static void +send_events(test_context *ctx, rtems_event_set events, size_t index) +{ + rtems_status_code sc; + + sc = rtems_event_send(ctx->worker_task[index], events); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void +start_worker(test_context *ctx) +{ + size_t i; + + for (i = 0; i < WORKER_COUNT; ++i) { + rtems_status_code sc; + + sc = rtems_task_create( + rtems_build_name('W', 'O', 'R', 'K'), + prio_worker[i], + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_FLOATING_POINT, + &ctx->worker_task[i] + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start( + ctx->worker_task[i], + worker_task, + i + ); + assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void +delete_worker(test_context *ctx) +{ + size_t i; + + for (i = 0; i < WORKER_COUNT; ++i) { + rtems_status_code sc; + + sc = rtems_task_delete(ctx->worker_task[i]); + assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void +test_mtx_non_recursive(test_context *ctx) +{ + struct mtx *mtx = &ctx->mtx; + + puts("test mtx non-recursive"); + + assert(!mtx_initialized(mtx)); + mtx_init(mtx, "test", NULL, MTX_DEF); + assert(mtx_initialized(mtx)); + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + mtx_unlock(mtx); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + mtx_destroy(mtx); + assert(!mtx_initialized(mtx)); +} + +static void +test_mtx_recursive(test_context *ctx) +{ + struct mtx *mtx = &ctx->mtx; + + puts("test mtx recursive"); + + assert(!mtx_initialized(mtx)); + mtx_init(mtx, "test", NULL, MTX_DEF | MTX_RECURSE); + assert(mtx_initialized(mtx)); + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 1); + mtx_lock(mtx); + + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 2); + + mtx_unlock(mtx); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 1); + + mtx_unlock(mtx); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + mtx_unlock(mtx); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + mtx_destroy(mtx); + assert(!mtx_initialized(mtx)); +} + +static void +test_mtx_trylock(test_context *ctx) +{ + size_t index = 0; + struct mtx *mtx = &ctx->mtx; + int ok; + + puts("test mtx try lock"); + + assert(!mtx_initialized(mtx)); + mtx_init(mtx, "test", NULL, MTX_DEF); + assert(mtx_initialized(mtx)); + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + ok = mtx_trylock(mtx); + assert(ok != 0); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + mtx_unlock(mtx); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + ctx->done[index] = false; + ctx->rv = 1; + send_events(ctx, EVENT_TRY_LOCK, index); + assert(ctx->done[index]); + assert(ctx->rv == 0); + + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_unlock(mtx); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + mtx_destroy(mtx); + assert(!mtx_initialized(mtx)); +} + +static void +test_mtx_lock(test_context *ctx) +{ + struct mtx *mtx = &ctx->mtx; + struct mtx *mtx2 = &ctx->mtx2; + size_t low = 0; + size_t high = 1; + + puts("test mtx lock"); + + assert(!mtx_initialized(mtx)); + mtx_init(mtx, "test", NULL, MTX_DEF); + assert(mtx_initialized(mtx)); + + assert(!mtx_initialized(mtx2)); + mtx_init(mtx2, "test 2", NULL, MTX_DEF); + assert(mtx_initialized(mtx2)); + + /* Resource count one */ + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == PRIO_MASTER); + + ctx->done[low] = false; + ctx->done[high] = false; + + send_events(ctx, EVENT_LOCK, low); + assert(!ctx->done[low]); + assert(!ctx->done[high]); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == prio_worker[low]); + + send_events(ctx, EVENT_LOCK, high); + assert(!ctx->done[low]); + assert(!ctx->done[high]); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == prio_worker[high]); + + mtx_unlock(mtx); + assert(!ctx->done[low]); + assert(ctx->done[high]); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == PRIO_MASTER); + + ctx->done[high] = false; + send_events(ctx, EVENT_UNLOCK, high); + assert(ctx->done[low]); + assert(ctx->done[high]); + + ctx->done[low] = false; + send_events(ctx, EVENT_UNLOCK, low); + assert(ctx->done[low]); + + /* Resource count two */ + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == PRIO_MASTER); + + assert(!mtx_owned(mtx2)); + assert(mtx_recursed(mtx2) == 0); + mtx_lock(mtx2); + assert(mtx_owned(mtx2)); + assert(mtx_recursed(mtx2) == 0); + assert(get_self_prio() == PRIO_MASTER); + + ctx->done[low] = false; + send_events(ctx, EVENT_LOCK, low); + assert(!ctx->done[low]); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == prio_worker[low]); + + mtx_unlock(mtx2); + assert(!mtx_owned(mtx2)); + assert(mtx_recursed(mtx2) == 0); + assert(get_self_prio() == prio_worker[low]); + + mtx_unlock(mtx); + assert(ctx->done[low]); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + assert(get_self_prio() == PRIO_MASTER); + + ctx->done[low] = false; + send_events(ctx, EVENT_UNLOCK, low); + assert(ctx->done[low]); + + mtx_destroy(mtx2); + assert(!mtx_initialized(mtx2)); + + mtx_destroy(mtx); + assert(!mtx_initialized(mtx)); +} + +static void +test_mtx_sleep_with_lock(test_context *ctx) +{ + size_t index = 0; + struct mtx *mtx = &ctx->mtx; + + puts("test mtx sleep with lock"); + + assert(!mtx_initialized(mtx)); + mtx_init(mtx, "test", NULL, MTX_DEF); + assert(mtx_initialized(mtx)); + + ctx->done[index] = false; + send_events(ctx, EVENT_LOCK, index); + assert(ctx->done[index]); + + ctx->done[index] = false; + ctx->timo = 0; + send_events(ctx, EVENT_SLEEP, index); + assert(!ctx->done[index]); + + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + mtx_lock(mtx); + assert(mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + wakeup(ctx); + assert(!ctx->done[index]); + + mtx_unlock(mtx); + assert(ctx->done[index]); + assert(!mtx_owned(mtx)); + assert(mtx_recursed(mtx) == 0); + + ctx->done[index] = false; + send_events(ctx, EVENT_UNLOCK, index); + assert(ctx->done[index]); + + mtx_destroy(mtx); + assert(!mtx_initialized(mtx)); +} + +static void +test_mtx_sleep_timeout(test_context *ctx) +{ + size_t index = 0; + struct mtx *mtx = &ctx->mtx; + rtems_status_code sc; + + puts("test mtx sleep timeout"); + + assert(!mtx_initialized(mtx)); + mtx_init(mtx, "test", NULL, MTX_DEF); + assert(mtx_initialized(mtx)); + + ctx->done[index] = false; + send_events(ctx, EVENT_LOCK, index); + assert(ctx->done[index]); + + ctx->done[index] = false; + ctx->timo = 2; + send_events(ctx, EVENT_SLEEP, index); + assert(!ctx->done[index]); + + sc = rtems_task_wake_after(ctx->timo); + assert(sc == RTEMS_SUCCESSFUL); + assert(ctx->done[index]); + + ctx->done[index] = false; + send_events(ctx, EVENT_UNLOCK, index); + assert(ctx->done[index]); + + mtx_destroy(mtx); + assert(!mtx_initialized(mtx)); +} + +static void +alloc_basic_resources(void) +{ + curthread; +} + +static void +test_main(void) +{ + test_context *ctx = &test_instance; + rtems_resource_snapshot snapshot_0; + rtems_resource_snapshot snapshot_1; + + alloc_basic_resources(); + + rtems_resource_snapshot_take(&snapshot_0); + + set_self_prio(PRIO_MASTER); + start_worker(ctx); + + rtems_resource_snapshot_take(&snapshot_1); + + test_mtx_non_recursive(ctx); + test_mtx_recursive(ctx); + test_mtx_trylock(ctx); + test_mtx_lock(ctx); + + assert(rtems_resource_snapshot_check(&snapshot_1)); + + test_mtx_sleep_with_lock(ctx); + test_mtx_sleep_timeout(ctx); + + delete_worker(ctx); + + assert(rtems_resource_snapshot_check(&snapshot_0)); + + exit(0); +} + +#include diff --git a/testsuite/rwlock01/test_main.c b/testsuite/rwlock01/test_main.c index fc4b2694..3e121c38 100644 --- a/testsuite/rwlock01/test_main.c +++ b/testsuite/rwlock01/test_main.c @@ -188,9 +188,6 @@ test_rw_non_recursive(test_context *ctx) rw_rlock(rw); /* FIXME: We use a mutex implementation */ assert(rw_wowned(rw)); - /* FIXME: We always allow recursion */ - rw_rlock(rw); - rw_runlock(rw); rw_runlock(rw); rw_rlock(rw); @@ -228,9 +225,6 @@ test_rw_non_recursive(test_context *ctx) rw_wlock(rw); assert(rw_wowned(rw)); - /* FIXME: We always allow recursion */ - rw_wlock(rw); - rw_wunlock(rw); rw_wunlock(rw); rw_wlock(rw); -- cgit v1.2.3