Update smpstrongapa01 to account for task shifting. --- spec/build/testsuites/smptests/grp.yml | 4 + .../testsuites/smptests/smpstrongapa02.yml | 21 + .../testsuites/smptests/smpstrongapa03.yml | 21 + testsuites/smptests/smpstrongapa01/init.c | 72 ++-- testsuites/smptests/smpstrongapa02/init.c | 373 ++++++++++++++++++ .../smpstrongapa02/smpstrongapa02.doc | 11 + .../smpstrongapa02/smpstrongapa02.scn | 2 + testsuites/smptests/smpstrongapa03/init.c | 358 +++++++++++++++++ .../smpstrongapa03/smpstrongapa03.doc | 11 + .../smpstrongapa03/smpstrongapa03.scn | 2 + 10 files changed, 846 insertions(+), 29 deletions(-) create mode 100644 spec/build/testsuites/smptests/smpstrongapa02.yml create mode 100644 spec/build/testsuites/smptests/smpstrongapa03.yml create mode 100644 testsuites/smptests/smpstrongapa02/init.c create mode 100644 testsuites/smptests/smpstrongapa02/smpstrongapa02.doc create mode 100644 testsuites/smptests/smpstrongapa02/smpstrongapa02.scn create mode 100644 testsuites/smptests/smpstrongapa03/init.c create mode 100644 testsuites/smptests/smpstrongapa03/smpstrongapa03.doc create mode 100644 testsuites/smptests/smpstrongapa03/smpstrongapa03.scn
diff --git a/spec/build/testsuites/smptests/grp.yml b/spec/build/testsuites/smptests/grp.yml index 771708503e..14b575e058 100644 --- a/spec/build/testsuites/smptests/grp.yml +++ b/spec/build/testsuites/smptests/grp.yml @@ -125,6 +125,10 @@ links: uid: smpsignal01 - role: build-dependency uid: smpstrongapa01 +- role: build-dependency + uid: smpstrongapa02 +- role: build-dependency + uid: smpstrongapa03 - role: build-dependency uid: smpswitchextension01 - role: build-dependency diff --git a/spec/build/testsuites/smptests/smpstrongapa02.yml b/spec/build/testsuites/smptests/smpstrongapa02.yml new file mode 100644 index 0000000000..56673c1cf0 --- /dev/null +++ b/spec/build/testsuites/smptests/smpstrongapa02.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +- Copyright (C) 2020 Richi Dubey (richidu...@gmail.com) +cppflags: [] +cxxflags: [] +enabled-by: +- RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/smptests/smpstrongapa02/init.c +stlib: [] +target: testsuites/smptests/smpstrongapa02.exe +type: build +use-after: [] +use-before: [] diff --git a/spec/build/testsuites/smptests/smpstrongapa03.yml b/spec/build/testsuites/smptests/smpstrongapa03.yml new file mode 100644 index 0000000000..50d08216b8 --- /dev/null +++ b/spec/build/testsuites/smptests/smpstrongapa03.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +- Copyright (C) 2020 Richi Dubey (richidu...@gmail.com) +cppflags: [] +cxxflags: [] +enabled-by: +- RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/smptests/smpstrongapa03/init.c +stlib: [] +target: testsuites/smptests/smpstrongapa03.exe +type: build +use-after: [] +use-before: [] diff --git a/testsuites/smptests/smpstrongapa01/init.c b/testsuites/smptests/smpstrongapa01/init.c index bf8bc05231..e7abacd519 100644 --- a/testsuites/smptests/smpstrongapa01/init.c +++ b/testsuites/smptests/smpstrongapa01/init.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2020 Richi Dubey ( richidu...@gmail.com ) * Copyright (c) 2016, 2017 embedded brains GmbH. All rights reserved. * * embedded brains GmbH @@ -16,23 +17,28 @@ #include "config.h" #endif -#include "tmacros.h" +#include <tmacros.h> #include <rtems.h> const char rtems_test_name[] = "SMPSTRONGAPA 1"; -#define CPU_COUNT 4 +#define CPU_COUNT 2 -#define TASK_COUNT (3 * CPU_COUNT) +#define TASK_COUNT 3 #define P(i) (UINT32_C(2) + i) #define ALL ((UINT32_C(1) << CPU_COUNT) - 1) -#define IDLE UINT8_C(255) +#define A(cpu0, cpu1) ( (cpu1 << 1) | cpu0 ) -#define NAME rtems_build_name('S', 'A', 'P', 'A') +typedef enum { + T0, + T1, + T2, + IDLE +} task_index; typedef struct { enum { @@ -43,7 +49,7 @@ typedef struct { KIND_UNBLOCK } kind; - size_t index; + task_index index; struct { rtems_task_priority priority; @@ -65,54 +71,59 @@ typedef struct { KIND_RESET, \ 0, \ { 0 }, \ - { IDLE, IDLE, IDLE, IDLE } \ + { IDLE, IDLE} \ } -#define SET_PRIORITY(index, prio, cpu0, cpu1, cpu2, cpu3) \ +#define SET_PRIORITY(index, prio, cpu0, cpu1) \ { \ KIND_SET_PRIORITY, \ index, \ { .priority = prio }, \ - { cpu0, cpu1, cpu2, cpu3 } \ + { cpu0, cpu1} \ } -#define SET_AFFINITY(index, aff, cpu0, cpu1, cpu2, cpu3) \ +#define SET_AFFINITY(index, aff, cpu0, cpu1) \ { \ KIND_SET_AFFINITY, \ index, \ { .cpu_set = aff }, \ - { cpu0, cpu1, cpu2, cpu3 } \ + { cpu0, cpu1 } \ } -#define BLOCK(index, cpu0, cpu1, cpu2, cpu3) \ +#define BLOCK(index, cpu0, cpu1) \ { \ KIND_BLOCK, \ index, \ { 0 }, \ - { cpu0, cpu1, cpu2, cpu3 } \ + { cpu0, cpu1 } \ } -#define UNBLOCK(index, cpu0, cpu1, cpu2, cpu3) \ +#define UNBLOCK(index, cpu0, cpu1) \ { \ KIND_UNBLOCK, \ index, \ { 0 }, \ - { cpu0, cpu1, cpu2, cpu3 } \ + { cpu0, cpu1} \ } static const test_action test_actions[] = { RESET, - UNBLOCK( 0, 0, IDLE, IDLE, IDLE), - UNBLOCK( 1, 0, 1, IDLE, IDLE), - UNBLOCK( 2, 0, 1, 2, IDLE), - UNBLOCK( 3, 0, 1, 2, 3), - UNBLOCK( 5, 0, 1, 2, 3), - SET_PRIORITY( 3, P(4), 0, 1, 2, 3), - SET_PRIORITY( 5, P(3), 0, 1, 2, 5), - BLOCK( 5, 0, 1, 2, 3), - SET_AFFINITY( 5, ALL, 0, 1, 2, 3), - RESET, - UNBLOCK( 0, 0, IDLE, IDLE, IDLE), + UNBLOCK( T0, T0, IDLE), + UNBLOCK( T1, T0, T1), + UNBLOCK( T2, T0, T1), + SET_PRIORITY( T0, P(0), T0, T1), + /* + * Introduce Task 2 intially with lowest priority to imitate late arrival + */ + SET_PRIORITY( T2, P(4), T0, T1), + SET_PRIORITY( T1, P(3), T0, T1), + SET_AFFINITY( T0, ALL, T0, T1), + SET_AFFINITY( T1, A(0, 1), T0, T1), + SET_AFFINITY( T2, A(1, 0), T0, T1), + /* + * Show that higher priority task gets dislodged from its processor + */ + SET_PRIORITY( T2, P(2), T2, T0), RESET }; @@ -182,7 +193,7 @@ static void check_cpu_allocations(test_context *ctx, const test_action *action) size_t i; for (i = 0; i < CPU_COUNT; ++i) { - size_t e; + task_index e; const Per_CPU_Control *c; const Thread_Control *h; @@ -279,7 +290,7 @@ static void test(void) for (i = 0; i < TASK_COUNT; ++i) { sc = rtems_task_create( - NAME, + rtems_build_name(' ', ' ', 'T', '0' + i), P(i), RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, @@ -292,7 +303,10 @@ static void test(void) rtems_test_assert(sc == RTEMS_SUCCESSFUL); } - sc = rtems_timer_create(NAME, &ctx->timer_id); + sc = rtems_timer_create( + rtems_build_name('A', 'C', 'T', 'N'), + &ctx->timer_id + ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); sc = rtems_timer_fire_after(ctx->timer_id, 1, timer, ctx); diff --git a/testsuites/smptests/smpstrongapa02/init.c b/testsuites/smptests/smpstrongapa02/init.c new file mode 100644 index 0000000000..accdc14279 --- /dev/null +++ b/testsuites/smptests/smpstrongapa02/init.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2020 Richi Dubey ( richidu...@gmail.com ) + * Copyright (c) 2016, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * 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> + +#include <rtems.h> + +const char rtems_test_name[] = "SMPSTRONGAPA 2"; + +#define CPU_COUNT 4 + +#define TASK_COUNT 5 + +#define P(i) (UINT32_C(2) + i) + +#define ALL ((UINT32_C(1) << CPU_COUNT) - 1) + +#define A(cpu0, cpu1, cpu2, cpu3) ( (cpu3 << 3) | (cpu2 << 2) | (cpu1 << 1)| cpu0 ) + +typedef enum { + T0, + T1, + T2, + T3, + T4, + IDLE +} task_index; + +typedef struct { + enum { + KIND_RESET, + KIND_SET_PRIORITY, + KIND_SET_AFFINITY, + KIND_BLOCK, + KIND_UNBLOCK + } kind; + + task_index index; + + struct { + rtems_task_priority priority; + uint32_t cpu_set; + } data; + + uint8_t expected_cpu_allocations[CPU_COUNT]; +} test_action; + +typedef struct { + rtems_id timer_id; + rtems_id master_id; + rtems_id task_ids[TASK_COUNT]; + size_t action_index; +} test_context; + +#define RESET \ + { \ + KIND_RESET, \ + 0, \ + { 0 }, \ + { IDLE, IDLE, IDLE, IDLE} \ + } + +#define SET_PRIORITY(index, prio, cpu0, cpu1, cpu2, cpu3) \ + { \ + KIND_SET_PRIORITY, \ + index, \ + { .priority = prio }, \ + { cpu0, cpu1, cpu2, cpu3} \ + } + +#define SET_AFFINITY(index, aff, cpu0, cpu1, cpu2, cpu3) \ + { \ + KIND_SET_AFFINITY, \ + index, \ + { .cpu_set = aff }, \ + { cpu0, cpu1, cpu2, cpu3 } \ + } + +#define BLOCK(index, cpu0, cpu1, cpu2, cpu3) \ + { \ + KIND_BLOCK, \ + index, \ + { 0 }, \ + { cpu0, cpu1, cpu2, cpu3 } \ + } + +#define UNBLOCK(index, cpu0, cpu1, cpu2, cpu3) \ + { \ + KIND_UNBLOCK, \ + index, \ + { 0 }, \ + { cpu0, cpu1, cpu2, cpu3} \ + } + +static const test_action test_actions[] = { + RESET, + UNBLOCK( T0, T0, IDLE, IDLE, IDLE), + UNBLOCK( T1, T0, T1, IDLE, IDLE), + UNBLOCK( T2, T0, T1, T2, IDLE), + UNBLOCK( T3, T0, T1, T2, T3), + UNBLOCK( T4, T0, T1, T2, T3), + SET_PRIORITY( T0, P(0), T0, T1, T2, T3), + SET_PRIORITY( T1, P(1), T0, T1, T2, T3), + SET_PRIORITY( T2, P(2), T0, T1, T2, T3), + SET_PRIORITY( T4, P(4), T0, T1, T2, T3), + /* + * Introduce Task 3 intially with lowest priority to imitate late arrival + */ + SET_PRIORITY( T3, P(8), T0, T1, T2, T4), + SET_AFFINITY( T0, ALL, T0, T1, T2, T4), + SET_AFFINITY( T1, A(0, 1, 0, 0), T0, T1, T2, T4), + SET_AFFINITY( T2, A(0, 0, 1, 0), T0, T1, T2, T4), + SET_AFFINITY( T4, A(0, 0, 0, 1), T0, T1, T2, T4), + /* + *Set affinity of Task 4 only to CPU1, so that we can check shifting + */ + SET_AFFINITY( T3, A(1, 0, 0, 0), T0, T1, T2, T4), + /* + * Show that higher priority task gets dislodged from its processor + * by a lower priority task ! + * and goes to the cpu that is executing the task with lowest priority + * (among all cpus). + */ + SET_PRIORITY( T3, P(3), T3, T1, T2, T0), + RESET +}; + +static test_context test_instance; + +static void set_priority(rtems_id id, rtems_task_priority prio) +{ + rtems_status_code sc; + + sc = rtems_task_set_priority(id, prio, &prio); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void set_affinity(rtems_id id, uint32_t cpu_set_32) +{ + rtems_status_code sc; + cpu_set_t cpu_set; + size_t i; + + CPU_ZERO(&cpu_set); + + for (i = 0; i < CPU_COUNT; ++i) { + if ((cpu_set_32 & (UINT32_C(1) << i)) != 0) { + CPU_SET(i, &cpu_set); + } + } + + sc = rtems_task_set_affinity(id, sizeof(cpu_set), &cpu_set); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void reset(test_context *ctx) +{ + rtems_status_code sc; + size_t i; + + for (i = CPU_COUNT; i < TASK_COUNT; ++i) { + set_priority(ctx->task_ids[i], P(i)); + set_affinity(ctx->task_ids[i], ALL); + + sc = rtems_task_suspend(ctx->task_ids[i]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL || sc == RTEMS_ALREADY_SUSPENDED); + } + + for (i = 0; i < CPU_COUNT; ++i) { + set_priority(ctx->task_ids[i], P(i)); + + sc = rtems_task_resume(ctx->task_ids[i]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL || sc == RTEMS_INCORRECT_STATE); + } + + /* Order the idle threads explicitly */ + for (i = 0; i < CPU_COUNT; ++i) { + const Per_CPU_Control *c; + const Thread_Control *h; + + c = _Per_CPU_Get_by_index(CPU_COUNT - 1 - i); + h = c->heir; + + sc = rtems_task_suspend(h->Object.id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void check_cpu_allocations(test_context *ctx, const test_action *action) +{ + size_t i; + + for (i = 0; i < CPU_COUNT; ++i) { + task_index e; + const Per_CPU_Control *c; + const Thread_Control *h; + + e = action->expected_cpu_allocations[i]; + c = _Per_CPU_Get_by_index(i); + h = c->heir; + + if (e != IDLE) { + rtems_test_assert(h->Object.id == ctx->task_ids[e]); + } else { + rtems_test_assert(h->is_idle); + } + } +} + +/* + * Use a timer to execute the actions, since it runs with thread dispatching + * disabled. This is necessary to check the expected processor allocations. + */ +static void timer(rtems_id id, void *arg) +{ + test_context *ctx; + rtems_status_code sc; + size_t i; + + ctx = arg; + i = ctx->action_index; + + if (i == 0) { + sc = rtems_task_suspend(ctx->master_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + if (i < RTEMS_ARRAY_SIZE(test_actions)) { + const test_action *action = &test_actions[i]; + rtems_id task; + + ctx->action_index = i + 1; + + task = ctx->task_ids[action->index]; + + switch (action->kind) { + case KIND_SET_PRIORITY: + set_priority(task, action->data.priority); + break; + case KIND_SET_AFFINITY: + set_affinity(task, action->data.cpu_set); + break; + case KIND_BLOCK: + sc = rtems_task_suspend(task); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + break; + case KIND_UNBLOCK: + sc = rtems_task_resume(task); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + break; + default: + rtems_test_assert(action->kind == KIND_RESET); + reset(ctx); + break; + } + + check_cpu_allocations(ctx, action); + + sc = rtems_timer_reset(id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } else { + sc = rtems_task_resume(ctx->master_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_send(ctx->master_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void do_nothing_task(rtems_task_argument arg) +{ + (void) arg; + + while (true) { + /* Do nothing */ + } +} + +static void test(void) +{ + test_context *ctx; + rtems_status_code sc; + size_t i; + + ctx = &test_instance; + + ctx->master_id = rtems_task_self(); + + for (i = 0; i < TASK_COUNT; ++i) { + sc = rtems_task_create( + rtems_build_name(' ', ' ', 'T', '0' + i), + P(i), + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->task_ids[i] + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(ctx->task_ids[i], do_nothing_task, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + sc = rtems_timer_create( + rtems_build_name('A', 'C', 'T', 'N'), + &ctx->timer_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_timer_fire_after(ctx->timer_id, 1, timer, ctx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + for (i = 0; i < TASK_COUNT; ++i) { + sc = rtems_task_delete(ctx->task_ids[i]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + sc = rtems_timer_delete(ctx->timer_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + if (rtems_scheduler_get_processor_maximum() == CPU_COUNT) { + test(); + } else { + puts("warning: wrong processor count to run the test"); + } + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS (1 + TASK_COUNT) +#define CONFIGURE_MAXIMUM_TIMERS 1 + +#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT + +#define CONFIGURE_SCHEDULER_STRONG_APA + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/smptests/smpstrongapa02/smpstrongapa02.doc b/testsuites/smptests/smpstrongapa02/smpstrongapa02.doc new file mode 100644 index 0000000000..aa85b97aa0 --- /dev/null +++ b/testsuites/smptests/smpstrongapa02/smpstrongapa02.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: smpstrongapa02 + +directives: + + TBD + +concepts: + + TBD diff --git a/testsuites/smptests/smpstrongapa02/smpstrongapa02.scn b/testsuites/smptests/smpstrongapa02/smpstrongapa02.scn new file mode 100644 index 0000000000..f88b160cad --- /dev/null +++ b/testsuites/smptests/smpstrongapa02/smpstrongapa02.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SMPSTRONGAPA 2 *** +*** END OF TEST SMPSTRONGAPA 2 *** diff --git a/testsuites/smptests/smpstrongapa03/init.c b/testsuites/smptests/smpstrongapa03/init.c new file mode 100644 index 0000000000..8683bbb28e --- /dev/null +++ b/testsuites/smptests/smpstrongapa03/init.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2020 Richi Dubey + * All rights reserved. + * + * richidu...@gmail.com + * + * 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> + +#include <rtems.h> + +const char rtems_test_name[] = "SMPSTRONGAPA 3"; + +#define CPU_COUNT 3 + +#define TASK_COUNT 4 + +#define P(i) (UINT32_C(2) + i) + +#define ALL ((UINT32_C(1) << CPU_COUNT) - 1) + +#define A(cpu0, cpu1, cpu2) ((cpu2 << 2) | (cpu1 << 1) | cpu0) + +typedef enum { + T0, + T1, + T2, + T3, + IDLE +} task_index; + +typedef struct { + enum { + KIND_RESET, + KIND_SET_PRIORITY, + KIND_SET_AFFINITY, + KIND_BLOCK, + KIND_UNBLOCK + } kind; + + task_index index; + + struct { + rtems_task_priority priority; + uint32_t cpu_set; + } data; + + uint8_t expected_cpu_allocations[CPU_COUNT]; +} test_action; + +typedef struct { + rtems_id timer_id; + rtems_id master_id; + rtems_id task_ids[TASK_COUNT]; + size_t action_index; +} test_context; + +#define RESET \ + { \ + KIND_RESET, \ + 0, \ + { 0 }, \ + { IDLE, IDLE, IDLE} \ + } + +#define SET_PRIORITY(index, prio, cpu0, cpu1, cpu2) \ + { \ + KIND_SET_PRIORITY, \ + index, \ + { .priority = prio }, \ + { cpu0, cpu1, cpu2 } \ + } + +#define SET_AFFINITY(index, aff, cpu0, cpu1, cpu2) \ + { \ + KIND_SET_AFFINITY, \ + index, \ + { .cpu_set = aff }, \ + { cpu0, cpu1, cpu2 } \ + } + +#define BLOCK(index, cpu0, cpu1, cpu2) \ + { \ + KIND_BLOCK, \ + index, \ + { 0 }, \ + { cpu0, cpu1, cpu2 } \ + } + +#define UNBLOCK(index, cpu0, cpu1, cpu2) \ + { \ + KIND_UNBLOCK, \ + index, \ + { 0 }, \ + { cpu0, cpu1, cpu2 } \ + } + +static const test_action test_actions[] = { + RESET, + UNBLOCK( T0, T0, IDLE, IDLE), + UNBLOCK( T1, T0, T1, IDLE), + UNBLOCK( T2, T0, T1, T2), + UNBLOCK( T3, T0, T1, T2), + SET_PRIORITY( T0, P(0), T0, T1, T2), + SET_PRIORITY( T1, P(1), T0, T1, T2), + SET_PRIORITY( T3, P(3), T0, T1, T2), + /* + * Introduce Task 2 intially with lowest priority to imitate late arrival + */ + SET_PRIORITY( T2, P(4), T0, T1, T3), + SET_AFFINITY( T0, ALL, T0, T1, T3), + SET_AFFINITY( T1, A(0, 1, 1), T0, T1, T3), + SET_AFFINITY( T2, A(1, 0, 0), T0, T1, T3), + SET_AFFINITY( T3, A(0, 1, 1), T0, T1, T3), + /* + * Show that higher priority task gets dislodged from its processor + */ + SET_PRIORITY( T2, P(2), T2, T1, T0), + RESET +}; + +static test_context test_instance; + +static void set_priority(rtems_id id, rtems_task_priority prio) +{ + rtems_status_code sc; + + sc = rtems_task_set_priority(id, prio, &prio); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void set_affinity(rtems_id id, uint32_t cpu_set_32) +{ + rtems_status_code sc; + cpu_set_t cpu_set; + size_t i; + + CPU_ZERO(&cpu_set); + + for (i = 0; i < CPU_COUNT; ++i) { + if ((cpu_set_32 & (UINT32_C(1) << i)) != 0) { + CPU_SET(i, &cpu_set); + } + } + + sc = rtems_task_set_affinity(id, sizeof(cpu_set), &cpu_set); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void reset(test_context *ctx) +{ + rtems_status_code sc; + size_t i; + + for (i = CPU_COUNT; i < TASK_COUNT; ++i) { + set_priority(ctx->task_ids[i], P(i)); + set_affinity(ctx->task_ids[i], ALL); + + sc = rtems_task_suspend(ctx->task_ids[i]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL || sc == RTEMS_ALREADY_SUSPENDED); + } + + for (i = 0; i < CPU_COUNT; ++i) { + set_priority(ctx->task_ids[i], P(i)); + + sc = rtems_task_resume(ctx->task_ids[i]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL || sc == RTEMS_INCORRECT_STATE); + } + + /* Order the idle threads explicitly */ + for (i = 0; i < CPU_COUNT; ++i) { + const Per_CPU_Control *c; + const Thread_Control *h; + + c = _Per_CPU_Get_by_index(CPU_COUNT - 1 - i); + h = c->heir; + + sc = rtems_task_suspend(h->Object.id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void check_cpu_allocations(test_context *ctx, const test_action *action) +{ + size_t i; + + for (i = 0; i < CPU_COUNT; ++i) { + task_index e; + const Per_CPU_Control *c; + const Thread_Control *h; + + e = action->expected_cpu_allocations[i]; + c = _Per_CPU_Get_by_index(i); + h = c->heir; + + if (e != IDLE) { + rtems_test_assert(h->Object.id == ctx->task_ids[e]); + } else { + rtems_test_assert(h->is_idle); + } + } +} + +/* + * Use a timer to execute the actions, since it runs with thread dispatching + * disabled. This is necessary to check the expected processor allocations. + */ +static void timer(rtems_id id, void *arg) +{ + test_context *ctx; + rtems_status_code sc; + size_t i; + + ctx = arg; + i = ctx->action_index; + + if (i == 0) { + sc = rtems_task_suspend(ctx->master_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + if (i < RTEMS_ARRAY_SIZE(test_actions)) { + const test_action *action = &test_actions[i]; + rtems_id task; + + ctx->action_index = i + 1; + + task = ctx->task_ids[action->index]; + + switch (action->kind) { + case KIND_SET_PRIORITY: + set_priority(task, action->data.priority); + break; + case KIND_SET_AFFINITY: + set_affinity(task, action->data.cpu_set); + break; + case KIND_BLOCK: + sc = rtems_task_suspend(task); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + break; + case KIND_UNBLOCK: + sc = rtems_task_resume(task); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + break; + default: + rtems_test_assert(action->kind == KIND_RESET); + reset(ctx); + break; + } + + check_cpu_allocations(ctx, action); + + sc = rtems_timer_reset(id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } else { + sc = rtems_task_resume(ctx->master_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_send(ctx->master_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } +} + +static void do_nothing_task(rtems_task_argument arg) +{ + (void) arg; + + while (true) { + /* Do nothing */ + } +} + +static void test(void) +{ + test_context *ctx; + rtems_status_code sc; + size_t i; + + ctx = &test_instance; + + ctx->master_id = rtems_task_self(); + + for (i = 0; i < TASK_COUNT; ++i) { + sc = rtems_task_create( + rtems_build_name(' ', ' ', 'T', '0' + i), + P(i), + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->task_ids[i] + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(ctx->task_ids[i], do_nothing_task, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + sc = rtems_timer_create( + rtems_build_name('A', 'C', 'T', 'N'), + &ctx->timer_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_timer_fire_after(ctx->timer_id, 1, timer, ctx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + for (i = 0; i < TASK_COUNT; ++i) { + sc = rtems_task_delete(ctx->task_ids[i]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + sc = rtems_timer_delete(ctx->timer_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + if (rtems_scheduler_get_processor_maximum() == CPU_COUNT) { + test(); + } else { + puts("warning: wrong processor count to run the test"); + } + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS (1 + TASK_COUNT) +#define CONFIGURE_MAXIMUM_TIMERS 1 + +#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT + +#define CONFIGURE_SCHEDULER_STRONG_APA + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/smptests/smpstrongapa03/smpstrongapa03.doc b/testsuites/smptests/smpstrongapa03/smpstrongapa03.doc new file mode 100644 index 0000000000..1bb5cfe69a --- /dev/null +++ b/testsuites/smptests/smpstrongapa03/smpstrongapa03.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: smpstrongapa03 + +directives: + + TBD + +concepts: + + TBD diff --git a/testsuites/smptests/smpstrongapa03/smpstrongapa03.scn b/testsuites/smptests/smpstrongapa03/smpstrongapa03.scn new file mode 100644 index 0000000000..996da1121f --- /dev/null +++ b/testsuites/smptests/smpstrongapa03/smpstrongapa03.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SMPSTRONGAPA 3 *** +*** END OF TEST SMPSTRONGAPA 3 *** -- 2.17.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel