/* * Copyright (c) 2013 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 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; 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) { rw_rlock(rw); ctx->done = true; } if ((events & EVENT_WLOCK) != 0) { rw_wlock(rw); ctx->done = true; } if ((events & EVENT_TRY_RLOCK) != 0) { ctx->rv = rw_try_rlock(rw); ctx->done = true; } if ((events & EVENT_TRY_WLOCK) != 0) { ctx->rv = rw_try_wlock(rw); ctx->done = true; } if ((events & EVENT_UNLOCK) != 0) { rw_unlock(rw); ctx->done = true; } if ((events & EVENT_SLEEP) != 0) { 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_FLOATING_POINT, &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)); 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)); 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) { curthread; } 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)); exit(0); } #include