diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-10-24 17:40:13 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-10-31 13:18:52 +0100 |
commit | 4adeb59b1875b8c3c20058fa4a1ada7e03a33519 (patch) | |
tree | 81e85e839aa9afee411df7a9e362215f96a04323 /testsuite/rwlock01 | |
parent | RWLOCK(9): Use RTEMS mutex to support recursion (diff) | |
download | rtems-libbsd-4adeb59b1875b8c3c20058fa4a1ada7e03a33519.tar.bz2 |
rwlock01: New test
Diffstat (limited to 'testsuite/rwlock01')
-rw-r--r-- | testsuite/rwlock01/test_main.c | 558 |
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> |