From 3995e6d9c213515f0d636dc2f211bf3c0d997631 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 2 Sep 2015 11:58:54 +0200 Subject: score: Implement SMP-specific priority queue --- testsuites/smptests/Makefile.am | 1 + testsuites/smptests/configure.ac | 1 + testsuites/smptests/smpmutex01/Makefile.am | 19 ++ testsuites/smptests/smpmutex01/init.c | 326 ++++++++++++++++++++++++++ testsuites/smptests/smpmutex01/smpmutex01.doc | 14 ++ testsuites/smptests/smpmutex01/smpmutex01.scn | 2 + 6 files changed, 363 insertions(+) create mode 100644 testsuites/smptests/smpmutex01/Makefile.am create mode 100644 testsuites/smptests/smpmutex01/init.c create mode 100644 testsuites/smptests/smpmutex01/smpmutex01.doc create mode 100644 testsuites/smptests/smpmutex01/smpmutex01.scn (limited to 'testsuites') diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am index 4b81a20b85..92f45286e5 100644 --- a/testsuites/smptests/Makefile.am +++ b/testsuites/smptests/Makefile.am @@ -26,6 +26,7 @@ SUBDIRS += smplock01 SUBDIRS += smpmigration01 SUBDIRS += smpmigration02 SUBDIRS += smpmrsp01 +SUBDIRS += smpmutex01 SUBDIRS += smpschedaffinity01 SUBDIRS += smpschedaffinity02 SUBDIRS += smpschedaffinity03 diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac index 5aee6ec34b..27e8f9c95a 100644 --- a/testsuites/smptests/configure.ac +++ b/testsuites/smptests/configure.ac @@ -81,6 +81,7 @@ smplock01/Makefile smpmigration01/Makefile smpmigration02/Makefile smpmrsp01/Makefile +smpmutex01/Makefile smppsxaffinity01/Makefile smppsxaffinity02/Makefile smppsxsignal01/Makefile diff --git a/testsuites/smptests/smpmutex01/Makefile.am b/testsuites/smptests/smpmutex01/Makefile.am new file mode 100644 index 0000000000..1b9e01c447 --- /dev/null +++ b/testsuites/smptests/smpmutex01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = smpmutex01 +smpmutex01_SOURCES = init.c + +dist_rtems_tests_DATA = smpmutex01.scn smpmutex01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(smpmutex01_OBJECTS) +LINK_LIBS = $(smpmutex01_LDLIBS) + +smpmutex01$(EXEEXT): $(smpmutex01_OBJECTS) $(smpmutex01_DEPENDENCIES) + @rm -f smpmutex01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/smptests/smpmutex01/init.c b/testsuites/smptests/smpmutex01/init.c new file mode 100644 index 0000000000..1b2a1895ef --- /dev/null +++ b/testsuites/smptests/smpmutex01/init.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2015 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 "tmacros.h" + +const char rtems_test_name[] = "SMPMUTEX 1"; + +#define SCHED_A rtems_build_name(' ', ' ', ' ', 'A') + +#define SCHED_B rtems_build_name(' ', ' ', ' ', 'B') + +#define PART_COUNT 2 + +#define TASK_COUNT 8 + +typedef enum { + REQ_WAKE_UP_MASTER = RTEMS_EVENT_0, + REQ_WAKE_UP_HELPER = RTEMS_EVENT_1, + REQ_MTX_OBTAIN = RTEMS_EVENT_2, + REQ_MTX_RELEASE = RTEMS_EVENT_3 +} request_id; + +typedef enum { + A_1, + A_2_0, + A_2_1, + M, + B_4, + B_5_0, + B_5_1, + H, + NONE +} task_id; + +typedef struct { + rtems_id mtx; + rtems_id tasks[TASK_COUNT]; + int generation[TASK_COUNT]; + int expected_generation[TASK_COUNT]; +} test_context; + +static test_context test_instance; + +static void start_task( + test_context *ctx, + task_id id, + rtems_task_entry entry, + rtems_task_priority prio, + rtems_name scheduler +) +{ + rtems_status_code sc; + rtems_id scheduler_id; + + sc = rtems_task_create( + rtems_build_name('T', 'A', 'S', 'K'), + prio, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->tasks[id] + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_scheduler_ident(scheduler, &scheduler_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_set_scheduler(ctx->tasks[id], scheduler_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(ctx->tasks[id], entry, id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void send_event(test_context *ctx, task_id id, rtems_event_set events) +{ + rtems_status_code sc; + + sc = rtems_event_send(ctx->tasks[id], events); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static rtems_event_set wait_for_events(void) +{ + rtems_event_set events; + rtems_status_code sc; + + sc = rtems_event_receive( + RTEMS_ALL_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + return events; +} + +static void sync_with_helper(test_context *ctx) +{ + rtems_event_set events; + + send_event(ctx, H, REQ_WAKE_UP_HELPER); + events = wait_for_events(); + rtems_test_assert(events == REQ_WAKE_UP_MASTER); +} + +static void request(test_context *ctx, task_id id, request_id req) +{ + send_event(ctx, id, req); + sync_with_helper(ctx); +} + +static void obtain(test_context *ctx) +{ + rtems_status_code sc; + + sc = rtems_semaphore_obtain(ctx->mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void release(test_context *ctx) +{ + rtems_status_code sc; + + sc = rtems_semaphore_release(ctx->mtx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void check_generations(test_context *ctx, task_id a, task_id b) +{ + size_t i; + + if (a != NONE) { + ++ctx->expected_generation[a]; + } + + if (b != NONE) { + ++ctx->expected_generation[b]; + } + + for (i = 0; i < TASK_COUNT; ++i) { + rtems_test_assert(ctx->generation[i] == ctx->expected_generation[i]); + } +} + +static void helper(rtems_task_argument arg) +{ + test_context *ctx = &test_instance; + + while (true) { + rtems_event_set events = wait_for_events(); + rtems_test_assert(events == REQ_WAKE_UP_HELPER); + send_event(ctx, M, REQ_WAKE_UP_MASTER); + } +} + +static void worker(rtems_task_argument arg) +{ + test_context *ctx = &test_instance; + task_id id = arg; + + while (true) { + rtems_event_set events = wait_for_events(); + + if ((events & REQ_MTX_OBTAIN) != 0) { + obtain(ctx); + ++ctx->generation[id]; + } + + if ((events & REQ_MTX_RELEASE) != 0) { + release(ctx); + ++ctx->generation[id]; + } + } +} + +static void test(void) +{ + test_context *ctx = &test_instance; + rtems_status_code sc; + + ctx->tasks[M] = rtems_task_self(); + start_task(ctx, A_1, worker, 1, SCHED_A); + start_task(ctx, A_2_0, worker, 2, SCHED_A); + start_task(ctx, A_2_1, worker, 2, SCHED_A); + start_task(ctx, B_4, worker, 4, SCHED_B); + start_task(ctx, B_5_0, worker, 5, SCHED_B); + start_task(ctx, B_5_1, worker, 5, SCHED_B); + start_task(ctx, H, helper, 6, SCHED_B); + + sc = rtems_semaphore_create( + rtems_build_name(' ', 'M', 'T', 'X'), + 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, + 0, + &ctx->mtx + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + obtain(ctx); + request(ctx, A_1, REQ_MTX_OBTAIN); + check_generations(ctx, NONE, NONE); + release(ctx); + check_generations(ctx, A_1, NONE); + request(ctx, A_1, REQ_MTX_RELEASE); + check_generations(ctx, A_1, NONE); + + obtain(ctx); + request(ctx, A_2_0, REQ_MTX_OBTAIN); + request(ctx, A_1, REQ_MTX_OBTAIN); + request(ctx, A_2_1, REQ_MTX_OBTAIN); + check_generations(ctx, NONE, NONE); + release(ctx); + check_generations(ctx, A_1, NONE); + request(ctx, A_1, REQ_MTX_RELEASE); + check_generations(ctx, A_1, A_2_0); + request(ctx, A_2_0, REQ_MTX_RELEASE); + check_generations(ctx, A_2_0, A_2_1); + request(ctx, A_2_1, REQ_MTX_RELEASE); + check_generations(ctx, A_2_1, NONE); + + obtain(ctx); + request(ctx, B_5_0, REQ_MTX_OBTAIN); + request(ctx, B_4, REQ_MTX_OBTAIN); + request(ctx, B_5_1, REQ_MTX_OBTAIN); + check_generations(ctx, NONE, NONE); + release(ctx); + sync_with_helper(ctx); + check_generations(ctx, B_4, NONE); + request(ctx, B_4, REQ_MTX_RELEASE); + check_generations(ctx, B_4, B_5_0); + request(ctx, B_5_0, REQ_MTX_RELEASE); + check_generations(ctx, B_5_0, B_5_1); + request(ctx, B_5_1, REQ_MTX_RELEASE); + check_generations(ctx, B_5_1, NONE); + + obtain(ctx); + request(ctx, A_2_0, REQ_MTX_OBTAIN); + request(ctx, B_5_0, REQ_MTX_OBTAIN); + request(ctx, B_5_1, REQ_MTX_OBTAIN); + request(ctx, B_4, REQ_MTX_OBTAIN); + request(ctx, A_2_1, REQ_MTX_OBTAIN); + request(ctx, A_1, REQ_MTX_OBTAIN); + check_generations(ctx, NONE, NONE); + release(ctx); + check_generations(ctx, A_1, NONE); + request(ctx, A_1, REQ_MTX_RELEASE); + check_generations(ctx, A_1, B_4); + request(ctx, B_4, REQ_MTX_RELEASE); + check_generations(ctx, B_4, A_2_0); + request(ctx, A_2_0, REQ_MTX_RELEASE); + check_generations(ctx, A_2_0, B_5_0); + request(ctx, B_5_0, REQ_MTX_RELEASE); + check_generations(ctx, B_5_0, A_2_1); + request(ctx, A_2_1, REQ_MTX_RELEASE); + check_generations(ctx, A_2_1, B_5_1); + request(ctx, B_5_1, REQ_MTX_RELEASE); + check_generations(ctx, B_5_1, NONE); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + if (rtems_get_processor_count() >= PART_COUNT) { + test(); + } + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM + +#define CONFIGURE_SMP_APPLICATION + +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS PART_COUNT + +#define CONFIGURE_SCHEDULER_SIMPLE_SMP + +#include + +RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a); + +RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b); + +#define CONFIGURE_SCHEDULER_CONTROLS \ + RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, SCHED_A), \ + RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, SCHED_B) + +#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \ + RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \ + RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL) + +#define CONFIGURE_MAXIMUM_TASKS TASK_COUNT + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_INIT_TASK_PRIORITY 3 + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/smptests/smpmutex01/smpmutex01.doc b/testsuites/smptests/smpmutex01/smpmutex01.doc new file mode 100644 index 0000000000..117d952e57 --- /dev/null +++ b/testsuites/smptests/smpmutex01/smpmutex01.doc @@ -0,0 +1,14 @@ +This file describes the directives and concepts tested by this test set. + +test set name: smpmutex01 + +directives: + + - _Thread_queue_Priority_do_enqueue() + - _Thread_queue_Priority_do_extract() + - _Thread_queue_Priority_first() + +concepts: + + - Ensure that the thread queue priority discipline enforces FIFO fairness + among the highest priority thread of each scheduler instance. diff --git a/testsuites/smptests/smpmutex01/smpmutex01.scn b/testsuites/smptests/smpmutex01/smpmutex01.scn new file mode 100644 index 0000000000..aad67a75c3 --- /dev/null +++ b/testsuites/smptests/smpmutex01/smpmutex01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SMPMUTEX 1 *** +*** END OF TEST SMPMUTEX 1 *** -- cgit v1.2.3