summaryrefslogtreecommitdiffstats
path: root/testsuite/rwlock01
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-10-24 17:40:13 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-10-31 13:18:52 +0100
commit4adeb59b1875b8c3c20058fa4a1ada7e03a33519 (patch)
tree81e85e839aa9afee411df7a9e362215f96a04323 /testsuite/rwlock01
parentRWLOCK(9): Use RTEMS mutex to support recursion (diff)
downloadrtems-libbsd-4adeb59b1875b8c3c20058fa4a1ada7e03a33519.tar.bz2
rwlock01: New test
Diffstat (limited to 'testsuite/rwlock01')
-rw-r--r--testsuite/rwlock01/test_main.c558
1 files changed, 558 insertions, 0 deletions
diff --git a/testsuite/rwlock01/test_main.c b/testsuite/rwlock01/test_main.c
new file mode 100644
index 00000000..e5015ab7
--- /dev/null
+++ b/testsuite/rwlock01/test_main.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * 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 <machine/rtems-bsd-config.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/types.h>
+#include <sys/systm.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/rwlock.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rtems/libcsupport.h>
+#include <rtems/stackchk.h>
+#include <rtems.h>
+
+#define TEST_NAME "LIBBSD RWLOCK 1"
+
+#define PRIO_MASTER 2
+
+#define PRIO_WORKER 1
+
+#define EVENT_RLOCK RTEMS_EVENT_0
+
+#define EVENT_WLOCK RTEMS_EVENT_1
+
+#define EVENT_TRY_RLOCK RTEMS_EVENT_2
+
+#define EVENT_TRY_WLOCK RTEMS_EVENT_3
+
+#define EVENT_UNLOCK RTEMS_EVENT_4
+
+#define EVENT_SLEEP RTEMS_EVENT_5
+
+typedef struct {
+ struct rwlock rw;
+ bool done;
+ int rv;
+ int timo;
+ rtems_id worker_task;
+} test_context;
+
+static test_context test_instance;
+
+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 arg)
+{
+ test_context *ctx = (test_context *) arg;
+ struct rwlock *rw = &ctx->rw;
+
+ puts("worker ready");
+
+ 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_RLOCK) != 0) {
+ puts("worker: rw_rlock");
+
+ rw_rlock(rw);
+ ctx->done = true;
+ }
+
+ if ((events & EVENT_WLOCK) != 0) {
+ puts("worker: rw_wlock");
+
+ rw_wlock(rw);
+ ctx->done = true;
+ }
+
+ if ((events & EVENT_TRY_RLOCK) != 0) {
+ puts("worker: rw_try_rlock");
+
+ ctx->rv = rw_try_rlock(rw);
+ ctx->done = true;
+ }
+
+ if ((events & EVENT_TRY_WLOCK) != 0) {
+ puts("worker: rw_try_wlock");
+
+ ctx->rv = rw_try_wlock(rw);
+ ctx->done = true;
+ }
+
+ if ((events & EVENT_UNLOCK) != 0) {
+ puts("worker: rw_unlock");
+
+ rw_unlock(rw);
+ ctx->done = true;
+ }
+
+ if ((events & EVENT_SLEEP) != 0) {
+ puts("worker: rw_sleep");
+
+ ctx->rv = rw_sleep(ctx, rw, 0, "worker", ctx->timo);
+ ctx->done = true;
+ }
+ }
+}
+
+static void
+send_events(test_context *ctx, rtems_event_set events)
+{
+ rtems_status_code sc;
+
+ sc = rtems_event_send(ctx->worker_task, events);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void
+start_worker(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_task_create(
+ rtems_build_name('W', 'O', 'R', 'K'),
+ PRIO_WORKER,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &ctx->worker_task
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_start(
+ ctx->worker_task,
+ worker_task,
+ (rtems_task_argument) ctx
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void
+delete_worker(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_task_delete(ctx->worker_task);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void
+test_rw_non_recursive(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+ int ok;
+
+ puts("test rw non-recursive");
+
+ assert(!rw_initialized(rw));
+ rw_init(rw, "test");
+ assert(rw_initialized(rw));
+
+ 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);
+ rw_unlock(rw);
+
+ rw_rlock(rw);
+ ok = rw_try_upgrade(rw);
+ assert(ok != 0);
+ assert(rw_wowned(rw));
+ rw_wunlock(rw);
+
+ rw_rlock(rw);
+ ok = rw_try_upgrade(rw);
+ assert(ok != 0);
+ assert(rw_wowned(rw));
+ rw_unlock(rw);
+
+ rw_rlock(rw);
+ ok = rw_try_upgrade(rw);
+ assert(ok != 0);
+ assert(rw_wowned(rw));
+ rw_downgrade(rw);
+ /* FIXME: We use a mutex implementation */
+ assert(rw_wowned(rw));
+ rw_runlock(rw);
+
+ rw_rlock(rw);
+ ok = rw_try_upgrade(rw);
+ assert(ok != 0);
+ assert(rw_wowned(rw));
+ rw_downgrade(rw);
+ /* FIXME: We use a mutex implementation */
+ assert(rw_wowned(rw));
+ rw_unlock(rw);
+
+ rw_wlock(rw);
+ assert(rw_wowned(rw));
+ /* FIXME: We always allow recursion */
+ rw_wlock(rw);
+ rw_wunlock(rw);
+ rw_wunlock(rw);
+
+ rw_wlock(rw);
+ rw_unlock(rw);
+
+ ok = rw_try_rlock(rw);
+ assert(ok != 0);
+ rw_unlock(rw);
+
+ ok = rw_try_wlock(rw);
+ assert(ok != 0);
+ rw_unlock(rw);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_recursive(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw recursive");
+
+ assert(!rw_initialized(rw));
+ rw_init_flags(rw, "test", RW_RECURSE);
+ assert(rw_initialized(rw));
+
+ rw_rlock(rw);
+ rw_rlock(rw);
+ rw_runlock(rw);
+ rw_runlock(rw);
+
+ rw_wlock(rw);
+ rw_wlock(rw);
+ rw_wunlock(rw);
+ rw_wunlock(rw);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_try_rlock(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw try rlock");
+
+ rw_init(rw, "test");
+
+ rw_rlock(rw);
+ /* FIXME: We use a mutex implementation */
+ ctx->done = false;
+ ctx->rv = 1;
+ send_events(ctx, EVENT_TRY_RLOCK);
+ assert(ctx->done);
+ assert(ctx->rv == 0);
+ rw_unlock(rw);
+
+ rw_wlock(rw);
+ ctx->done = false;
+ ctx->rv = 1;
+ send_events(ctx, EVENT_TRY_RLOCK);
+ assert(ctx->done);
+ assert(ctx->rv == 0);
+ rw_unlock(rw);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_try_wlock(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw try wlock");
+
+ rw_init(rw, "test");
+
+ rw_rlock(rw);
+ ctx->done = false;
+ ctx->rv = 1;
+ send_events(ctx, EVENT_TRY_WLOCK);
+ assert(ctx->done);
+ assert(ctx->rv == 0);
+ rw_unlock(rw);
+
+ rw_wlock(rw);
+ ctx->done = false;
+ ctx->rv = 1;
+ send_events(ctx, EVENT_TRY_WLOCK);
+ assert(ctx->done);
+ assert(ctx->rv == 0);
+ rw_unlock(rw);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_rlock(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw rlock");
+
+ rw_init(rw, "test");
+
+ rw_rlock(rw);
+ /* FIXME: We use a mutex implementation */
+ ctx->done = false;
+ send_events(ctx, EVENT_RLOCK);
+ assert(!ctx->done);
+ rw_unlock(rw);
+ assert(ctx->done);
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_wlock(rw);
+ ctx->done = false;
+ send_events(ctx, EVENT_RLOCK);
+ assert(!ctx->done);
+ rw_unlock(rw);
+ assert(ctx->done);
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_wlock(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw rlock");
+
+ rw_init(rw, "test");
+
+ rw_rlock(rw);
+ ctx->done = false;
+ send_events(ctx, EVENT_WLOCK);
+ assert(!ctx->done);
+ rw_unlock(rw);
+ assert(ctx->done);
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_wlock(rw);
+ ctx->done = false;
+ send_events(ctx, EVENT_WLOCK);
+ assert(!ctx->done);
+ rw_unlock(rw);
+ assert(ctx->done);
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_sleep_with_rlock(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw sleep with rlock");
+
+ rw_init(rw, "test");
+
+ ctx->done = false;
+ send_events(ctx, EVENT_RLOCK);
+ assert(ctx->done);
+
+ ctx->done = false;
+ ctx->timo = 0;
+ send_events(ctx, EVENT_SLEEP);
+ assert(!ctx->done);
+
+ rw_rlock(rw);
+ wakeup(ctx);
+ /* FIXME: We use a mutex implementation */
+ assert(!ctx->done);
+ rw_unlock(rw);
+ /* FIXME: We use a mutex implementation */
+ assert(ctx->done);
+
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_sleep_with_wlock(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+
+ puts("test rw sleep with wlock");
+
+ rw_init(rw, "test");
+
+ ctx->done = false;
+ send_events(ctx, EVENT_WLOCK);
+ assert(ctx->done);
+
+ ctx->done = false;
+ ctx->timo = 0;
+ send_events(ctx, EVENT_SLEEP);
+ assert(!ctx->done);
+
+ rw_rlock(rw);
+ wakeup(ctx);
+ assert(!ctx->done);
+ rw_unlock(rw);
+ assert(ctx->done);
+
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_destroy(rw);
+}
+
+static void
+test_rw_sleep_timeout(test_context *ctx)
+{
+ struct rwlock *rw = &ctx->rw;
+ rtems_status_code sc;
+
+ puts("test rw sleep timeout");
+
+ rw_init(rw, "test");
+
+ ctx->done = false;
+ send_events(ctx, EVENT_RLOCK);
+ assert(ctx->done);
+
+ ctx->done = false;
+ ctx->timo = 2;
+ send_events(ctx, EVENT_SLEEP);
+ assert(!ctx->done);
+
+ sc = rtems_task_wake_after(ctx->timo);
+ assert(sc == RTEMS_SUCCESSFUL);
+
+ assert(ctx->done);
+
+ ctx->done = false;
+ send_events(ctx, EVENT_UNLOCK);
+ assert(ctx->done);
+
+ rw_destroy(rw);
+}
+
+static void
+alloc_basic_resources(void)
+{
+ rtems_status_code sc;
+
+ curthread;
+
+ sc = rtems_task_wake_after(2);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void
+test_main(void)
+{
+ rtems_resource_snapshot snapshot_0;
+ rtems_resource_snapshot snapshot_1;
+
+ test_context *ctx = &test_instance;
+
+ alloc_basic_resources();
+
+ rtems_resource_snapshot_take(&snapshot_0);
+
+ set_self_prio(PRIO_MASTER);
+ start_worker(ctx);
+
+ rtems_resource_snapshot_take(&snapshot_1);
+
+ test_rw_non_recursive(ctx);
+ test_rw_recursive(ctx);
+ test_rw_try_rlock(ctx);
+ test_rw_try_wlock(ctx);
+ test_rw_rlock(ctx);
+ test_rw_wlock(ctx);
+
+ assert(rtems_resource_snapshot_check(&snapshot_1));
+
+ test_rw_sleep_with_rlock(ctx);
+ test_rw_sleep_with_wlock(ctx);
+ test_rw_sleep_timeout(ctx);
+
+ delete_worker(ctx);
+
+ assert(rtems_resource_snapshot_check(&snapshot_0));
+
+ rtems_stack_checker_report_usage_with_plugin(NULL,
+ rtems_printf_plugin);
+
+ puts("*** END OF " TEST_NAME " TEST ***");
+ exit(0);
+}
+
+#include <rtems/bsd/test/default-init.h>