/* * Copyright (c) 2014, 2016 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "tmacros.h" #define PRIO_INIT 1 #define PRIO_HIGH 2 #define PRIO_MID 3 #define PRIO_LOW 4 #define PRIO_VERY_LOW 5 const char rtems_test_name[] = "SPTHREADLIFE 1"; typedef enum { INIT, SET_PRIO, SET_PRIO_DONE, DO_OBTAIN_0, OBTAIN_DONE_0, DO_RELEASE_0, RELEASE_DONE_0, DO_OBTAIN_1, OBTAIN_DONE_1, RESTART_0, RESTART_1, RESTART_2, RESTART_3, DO_RELEASE_1, RELEASE_DONE_1, DELETE_0, DELETE_1, DELETE_2, DELETE_3, SET_PROTECTION, SET_PROTECTION_DONE, CLEAR_PROTECTION, DELETE_4, DELETE_5, DELETE_6, DELETE_SELF, DELETE_7, DELETE_8, DELETE_9, INVALID } test_state; typedef struct { rtems_id main_task_id; rtems_id worker_task_id; rtems_id sema_id; test_state current; test_state next; } test_context; static test_context test_instance; static void wake_up_main(const test_context *ctx) { rtems_status_code sc; sc = rtems_event_transient_send(ctx->main_task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } static void wait(void) { rtems_status_code sc; sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } static void change_state( test_context *ctx, test_state expected, test_state current, test_state next ) { rtems_test_assert(ctx->current == expected); ctx->current = current; ctx->next = next; } static void change_state_and_wait( test_context *ctx, test_state expected, test_state current, test_state next ) { change_state(ctx, expected, current, next); wait(); } static void set_priority(rtems_task_priority prio) { rtems_status_code sc; sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } static void assert_priority(rtems_task_priority expected) { rtems_status_code sc; rtems_task_priority prio; sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &prio); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(prio == expected); } static void restart_extension( Thread_Control *executing, Thread_Control *restarted ) { test_context *ctx = &test_instance; rtems_status_code sc; rtems_test_assert(executing == restarted); switch (ctx->current) { case RESTART_0: rtems_test_assert(ctx->worker_task_id == rtems_task_self()); ctx->current = RESTART_1; sc = rtems_task_restart(RTEMS_SELF, 0); rtems_test_assert(sc == RTEMS_SUCCESSFUL); break; case RESTART_1: rtems_test_assert(ctx->worker_task_id == rtems_task_self()); ctx->current = RESTART_2; break; case INIT: /* Restart via _Thread_Global_construction() */ break; default: rtems_test_assert(0); break; } } static void delete_extension( Thread_Control *executing, Thread_Control *deleted ) { test_context *ctx = &test_instance; rtems_test_assert(executing != deleted); rtems_test_assert(ctx->main_task_id == rtems_task_self()); switch (ctx->current) { case DELETE_2: assert_priority(PRIO_INIT); ctx->current = DELETE_3; break; case DELETE_5: assert_priority(PRIO_INIT); ctx->current = DELETE_6; break; case DELETE_8: assert_priority(PRIO_VERY_LOW); ctx->current = DELETE_9; break; default: rtems_test_assert(0); break; } } static void terminate_extension(Thread_Control *executing) { test_context *ctx = &test_instance; rtems_status_code sc; rtems_test_assert(ctx->worker_task_id == rtems_task_self()); switch (ctx->current) { case DELETE_0: assert_priority(PRIO_INIT); ctx->current = DELETE_1; sc = rtems_task_delete(RTEMS_SELF); rtems_test_assert(sc == RTEMS_SUCCESSFUL); break; case DELETE_1: assert_priority(PRIO_INIT); ctx->current = DELETE_2; break; case DELETE_4: assert_priority(PRIO_INIT); ctx->current = DELETE_5; break; case DELETE_7: assert_priority(PRIO_LOW); ctx->current = DELETE_8; wake_up_main(ctx); break; default: rtems_test_assert(0); break; } } static void worker_task(rtems_task_argument arg) { test_context *ctx = &test_instance; while (true) { test_state state = ctx->current; rtems_status_code sc; Thread_Life_state previous_thread_life_state; Per_CPU_Control *cpu_self; switch (state) { case SET_PRIO: assert_priority(PRIO_LOW); set_priority(PRIO_MID); break; case DO_OBTAIN_0: case DO_OBTAIN_1: assert_priority(PRIO_MID); sc = rtems_semaphore_obtain( ctx->sema_id, RTEMS_WAIT, RTEMS_NO_TIMEOUT ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); assert_priority(PRIO_HIGH); break; case DO_RELEASE_0: case DO_RELEASE_1: assert_priority(PRIO_HIGH); sc = rtems_semaphore_release(ctx->sema_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); switch (state) { case DO_RELEASE_0: assert_priority(PRIO_MID); break; case DO_RELEASE_1: assert_priority(PRIO_LOW); break; default: rtems_test_assert(0); break; } break; case RESTART_2: assert_priority(PRIO_HIGH); break; case SET_PROTECTION: cpu_self = _Thread_Dispatch_disable(); previous_thread_life_state = _Thread_Set_life_protection(THREAD_LIFE_PROTECTED); rtems_test_assert( (previous_thread_life_state & THREAD_LIFE_PROTECTED) == 0 ); _Thread_Dispatch_enable(cpu_self); break; case CLEAR_PROTECTION: cpu_self = _Thread_Dispatch_disable(); previous_thread_life_state = _Thread_Set_life_protection(0); rtems_test_assert( (previous_thread_life_state & THREAD_LIFE_PROTECTED) != 0 ); ctx->current = DELETE_4; _Thread_Dispatch_enable(cpu_self); break; case DELETE_SELF: ctx->current = DELETE_7; rtems_task_delete(RTEMS_SELF); rtems_test_assert(0); break; default: rtems_test_assert(0); break; } ctx->current = ctx->next; wake_up_main(ctx); } } static void create_sema(test_context *ctx) { rtems_status_code sc; sc = rtems_semaphore_create( rtems_build_name('S', 'E', 'M', 'A'), 1, RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING, PRIO_HIGH, &ctx->sema_id ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } static void create_and_start_worker(test_context *ctx) { rtems_status_code sc; sc = rtems_task_create( rtems_build_name('W', 'O', 'R', 'K'), PRIO_LOW, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &ctx->worker_task_id ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); sc = rtems_task_start(ctx->worker_task_id, worker_task, 0); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } static void test(void) { test_context *ctx = &test_instance; rtems_status_code sc; rtems_resource_snapshot snapshot; ctx->main_task_id = rtems_task_self(); rtems_resource_snapshot_take(&snapshot); create_sema(ctx); create_and_start_worker(ctx); change_state_and_wait(ctx, INIT, SET_PRIO, SET_PRIO_DONE); change_state_and_wait(ctx, SET_PRIO_DONE, DO_OBTAIN_0, OBTAIN_DONE_0); sc = rtems_semaphore_delete(ctx->sema_id); rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE); change_state_and_wait(ctx, OBTAIN_DONE_0, DO_RELEASE_0, RELEASE_DONE_0); sc = rtems_semaphore_delete(ctx->sema_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); create_sema(ctx); change_state_and_wait(ctx, RELEASE_DONE_0, DO_OBTAIN_1, OBTAIN_DONE_1); sc = rtems_semaphore_delete(ctx->sema_id); rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE); sc = rtems_task_restart(ctx->worker_task_id, 0); rtems_test_assert(sc == RTEMS_SUCCESSFUL); change_state_and_wait(ctx, OBTAIN_DONE_1, RESTART_0, RESTART_3); change_state_and_wait(ctx, RESTART_3, DO_RELEASE_1, RELEASE_DONE_1); sc = rtems_semaphore_delete(ctx->sema_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); change_state(ctx, RELEASE_DONE_1, DELETE_0, INVALID); sc = rtems_task_delete(ctx->worker_task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(ctx->current == DELETE_2); rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); create_and_start_worker(ctx); change_state_and_wait(ctx, DELETE_3, SET_PROTECTION, SET_PROTECTION_DONE); change_state(ctx, SET_PROTECTION_DONE, CLEAR_PROTECTION, INVALID); sc = rtems_task_delete(ctx->worker_task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); create_and_start_worker(ctx); change_state(ctx, DELETE_6, DELETE_SELF, INVALID); set_priority(PRIO_VERY_LOW); rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); rtems_test_assert(ctx->current == DELETE_9); } static void Init(rtems_task_argument arg) { TEST_BEGIN(); test(); TEST_END(); rtems_test_exit(0); } #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER #define CONFIGURE_MAXIMUM_TASKS 2 #define CONFIGURE_MAXIMUM_SEMAPHORES 1 #define CONFIGURE_INITIAL_EXTENSIONS \ { \ .thread_restart = restart_extension, \ .thread_delete = delete_extension, \ .thread_terminate = terminate_extension \ }, \ RTEMS_TEST_INITIAL_EXTENSION #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES #define CONFIGURE_RTEMS_INIT_TASKS_TABLE #define CONFIGURE_INIT #include