[PATCH v6 2/2] Update smpstrongapa01; Add smpstrongapa02,smpstrongapa03

Richi Dubey richidubey at gmail.com
Wed Jun 16 06:00:17 UTC 2021


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 (richidubey at 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 (richidubey at 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 ( richidubey at 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 ( richidubey at gmail.com )
+ * Copyright (c) 2016, 2017 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.
+ *
+ * richidubey at 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



More information about the devel mailing list