diff options
Diffstat (limited to 'test')
30 files changed, 5348 insertions, 4527 deletions
diff --git a/test/nil/configuration.xml b/test/nil/configuration.xml index 710e9a3be..d58582dd8 100644 --- a/test/nil/configuration.xml +++ b/test/nil/configuration.xml @@ -82,6 +82,156 @@ THD_FUNCTION(test_support, arg) {                <value>Internal Tests</value>
              </type>
              <brief>
 +              <value>Information.</value>
 +            </brief>
 +            <description>
 +              <value>This sequence reports configuration and version information about the NIL kernel.</value>
 +            </description>
 +            <condition>
 +              <value />
 +            </condition>
 +            <shared_code>
 +              <value><![CDATA[#include "ch.h"]]></value>
 +            </shared_code>
 +            <cases>
 +              <case>
 +                <brief>
 +                  <value>Kernel Info.</value>
 +                </brief>
 +                <description>
 +                  <value>The version numbers are reported.</value>
 +                </description>
 +                <condition>
 +                  <value />
 +                </condition>
 +                <various_code>
 +                  <setup_code>
 +                    <value />
 +                  </setup_code>
 +                  <teardown_code>
 +                    <value />
 +                  </teardown_code>
 +                  <local_variables>
 +                    <value />
 +                  </local_variables>
 +                </various_code>
 +                <steps>
 +                  <step>
 +                    <description>
 +                      <value>Prints the version string.</value>
 +                    </description>
 +                    <tags>
 +                      <value />
 +                    </tags>
 +                    <code>
 +                      <value><![CDATA[test_println("*** Product:                   ChibiOS/NIL");
 +test_print("*** Stable Flag:               ");
 +test_printn(CH_KERNEL_STABLE);
 +test_println("");
 +test_print("*** Version String:            ");
 +test_println(CH_KERNEL_VERSION);
 +test_print("*** Major Number:              ");
 +test_printn(CH_KERNEL_MAJOR);
 +test_println("");
 +test_print("*** Minor Number:              ");
 +test_printn(CH_KERNEL_MINOR);
 +test_println("");
 +test_print("*** Patch Number:              ");
 +test_printn(CH_KERNEL_PATCH);
 +test_println("");]]></value>
 +                    </code>
 +                  </step>
 +                </steps>
 +              </case>
 +              <case>
 +                <brief>
 +                  <value>Kernel Settings.</value>
 +                </brief>
 +                <description>
 +                  <value>The static kernel settings are reported.</value>
 +                </description>
 +                <condition>
 +                  <value />
 +                </condition>
 +                <various_code>
 +                  <setup_code>
 +                    <value />
 +                  </setup_code>
 +                  <teardown_code>
 +                    <value />
 +                  </teardown_code>
 +                  <local_variables>
 +                    <value />
 +                  </local_variables>
 +                </various_code>
 +                <steps>
 +                  <step>
 +                    <description>
 +                      <value>Prints the configuration options settings.</value>
 +                    </description>
 +                    <tags>
 +                      <value />
 +                    </tags>
 +                    <code>
 +                      <value><![CDATA[test_print("*** CH_CFG_NUM_THREADS:        ");
 +test_printn(CH_CFG_NUM_THREADS);
 +test_println("");
 +test_print("*** CH_CFG_ST_RESOLUTION:      ");
 +test_printn(CH_CFG_ST_RESOLUTION);
 +test_println("");
 +test_print("*** CH_CFG_ST_FREQUENCY:       ");
 +test_printn(CH_CFG_ST_FREQUENCY);
 +test_println("");
 +test_print("*** CH_CFG_ST_TIMEDELTA:       ");
 +test_printn(CH_CFG_ST_TIMEDELTA);
 +test_println("");
 +test_print("*** CH_CFG_USE_SEMAPHORES:     ");
 +test_printn(CH_CFG_USE_SEMAPHORES);
 +test_println("");
 +test_print("*** CH_CFG_USE_MUTEXES:        ");
 +test_printn(CH_CFG_USE_MUTEXES);
 +test_println("");
 +test_print("*** CH_CFG_USE_EVENTS:         ");
 +test_printn(CH_CFG_USE_EVENTS);
 +test_println("");
 +test_print("*** CH_CFG_USE_MAILBOXES:      ");
 +test_printn(CH_CFG_USE_MAILBOXES);
 +test_println("");
 +test_print("*** CH_CFG_USE_MEMCORE:        ");
 +test_printn(CH_CFG_USE_MEMCORE);
 +test_println("");
 +test_print("*** CH_CFG_USE_HEAP:           ");
 +test_printn(CH_CFG_USE_HEAP);
 +test_println("");
 +test_print("*** CH_CFG_USE_MEMPOOLS:       ");
 +test_printn(CH_CFG_USE_MEMPOOLS);
 +test_println("");
 +test_print("*** CH_DBG_STATISTICS:         ");
 +test_printn(CH_DBG_STATISTICS);
 +test_println("");
 +test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
 +test_printn(CH_DBG_SYSTEM_STATE_CHECK);
 +test_println("");
 +test_print("*** CH_DBG_ENABLE_CHECKS:      ");
 +test_printn(CH_DBG_ENABLE_CHECKS);
 +test_println("");
 +test_print("*** CH_DBG_ENABLE_ASSERTS:     ");
 +test_printn(CH_DBG_ENABLE_ASSERTS);
 +test_println("");
 +test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
 +test_printn(CH_DBG_ENABLE_STACK_CHECK);
 +test_println("");]]></value>
 +                    </code>
 +                  </step>
 +                </steps>
 +              </case>
 +            </cases>
 +          </sequence>
 +          <sequence>
 +            <type index="0">
 +              <value>Internal Tests</value>
 +            </type>
 +            <brief>
                <value>Threads Functionality.</value>
              </brief>
              <description>
 diff --git a/test/nil/source/test/test_root.c b/test/nil/source/test/test_root.c index 177a46853..a41bb56bc 100644 --- a/test/nil/source/test/test_root.c +++ b/test/nil/source/test/test_root.c @@ -27,6 +27,7 @@   * - @subpage test_sequence_004
   * - @subpage test_sequence_005
   * - @subpage test_sequence_006
 + * - @subpage test_sequence_007
   * .
   */
 @@ -50,18 +51,19 @@   */
  const testcase_t * const *test_suite[] = {
    test_sequence_001,
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    test_sequence_002,
 -#endif
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    test_sequence_003,
 -#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
 +#endif
    test_sequence_004,
 +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
 +  test_sequence_005,
  #endif
  #if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
 -  test_sequence_005,
 +  test_sequence_006,
  #endif
  #if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
 -  test_sequence_006,
 +  test_sequence_007,
  #endif
    NULL
  };
 diff --git a/test/nil/source/test/test_root.h b/test/nil/source/test/test_root.h index 694abf9c5..a5b5d6958 100644 --- a/test/nil/source/test/test_root.h +++ b/test/nil/source/test/test_root.h @@ -28,6 +28,7 @@  #include "test_sequence_004.h"
  #include "test_sequence_005.h"
  #include "test_sequence_006.h"
 +#include "test_sequence_007.h"
  #if !defined(__DOXYGEN__)
 diff --git a/test/nil/source/test/test_sequence_001.c b/test/nil/source/test/test_sequence_001.c index df99ee49b..683a26f3f 100644 --- a/test/nil/source/test/test_sequence_001.c +++ b/test/nil/source/test/test_sequence_001.c @@ -22,13 +22,13 @@   * @file    test_sequence_001.c
   * @brief   Test Sequence 001 code.
   *
 - * @page test_sequence_001 [1] Threads Functionality
 + * @page test_sequence_001 [1] Information
   *
   * File: @ref test_sequence_001.c
   *
   * <h2>Description</h2>
 - * This sequence tests the ChibiOS/NIL functionalities related to
 - * threading.
 + * This sequence reports configuration and version information about
 + * the NIL kernel.
   *
   * <h2>Test Cases</h2>
   * - @subpage test_001_001
 @@ -47,123 +47,115 @@   ****************************************************************************/
  /**
 - * @page test_001_001 [1.1] System Tick Counter functionality
 + * @page test_001_001 [1.1] Kernel Info
   *
   * <h2>Description</h2>
 - * The functionality of the API @p chVTGetSystemTimeX() is tested.
 + * The version numbers are reported.
   *
   * <h2>Test Steps</h2>
 - * - [1.1.1] A System Tick Counter increment is expected, the test
 - *   simply hangs if it does not happen.
 + * - [1.1.1] Prints the version string.
   * .
   */
  static void test_001_001_execute(void) {
 -  /* [1.1.1] A System Tick Counter increment is expected, the test
 -     simply hangs if it does not happen.*/
 +  /* [1.1.1] Prints the version string.*/
    test_set_step(1);
    {
 -    systime_t time = chVTGetSystemTimeX();
 -    while (time == chVTGetSystemTimeX()) {
 -    }
 +    test_println("*** Product:                   ChibiOS/NIL");
 +    test_print("*** Stable Flag:               ");
 +    test_printn(CH_KERNEL_STABLE);
 +    test_println("");
 +    test_print("*** Version String:            ");
 +    test_println(CH_KERNEL_VERSION);
 +    test_print("*** Major Number:              ");
 +    test_printn(CH_KERNEL_MAJOR);
 +    test_println("");
 +    test_print("*** Minor Number:              ");
 +    test_printn(CH_KERNEL_MINOR);
 +    test_println("");
 +    test_print("*** Patch Number:              ");
 +    test_printn(CH_KERNEL_PATCH);
 +    test_println("");
    }
  }
  static const testcase_t test_001_001 = {
 -  "System Tick Counter functionality",
 +  "Kernel Info",
    NULL,
    NULL,
    test_001_001_execute
  };
  /**
 - * @page test_001_002 [1.2] Thread Sleep functionality
 + * @page test_001_002 [1.2] Kernel Settings
   *
   * <h2>Description</h2>
 - * The functionality of @p chThdSleep() and derivatives is tested.
 + * The static kernel settings are reported.
   *
   * <h2>Test Steps</h2>
 - * - [1.2.1] The current system time is read then a sleep is performed
 - *   for 100 system ticks and on exit the system time is verified
 - *   again.
 - * - [1.2.2] The current system time is read then a sleep is performed
 - *   for 100000 microseconds and on exit the system time is verified
 - *   again.
 - * - [1.2.3] The current system time is read then a sleep is performed
 - *   for 100 milliseconds and on exit the system time is verified
 - *   again.
 - * - [1.2.4] The current system time is read then a sleep is performed
 - *   for 1 second and on exit the system time is verified again.
 - * - [1.2.5] Function chThdSleepUntil() is tested with a timeline of
 - *   "now" + 100 ticks.
 + * - [1.2.1] Prints the configuration options settings.
   * .
   */
  static void test_001_002_execute(void) {
 -  systime_t time;
 -  /* [1.2.1] The current system time is read then a sleep is performed
 -     for 100 system ticks and on exit the system time is verified
 -     again.*/
 +  /* [1.2.1] Prints the configuration options settings.*/
    test_set_step(1);
    {
 -    time = chVTGetSystemTimeX();
 -    chThdSleep(100);
 -    test_assert_time_window(time + 100,
 -                            time + 100 + 1,
 -                            "out of time window");
 -  }
 -
 -  /* [1.2.2] The current system time is read then a sleep is performed
 -     for 100000 microseconds and on exit the system time is verified
 -     again.*/
 -  test_set_step(2);
 -  {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepMicroseconds(100000);
 -    test_assert_time_window(time + US2ST(100000),
 -                            time + US2ST(100000) + 1,
 -                            "out of time window");
 -  }
 -
 -  /* [1.2.3] The current system time is read then a sleep is performed
 -     for 100 milliseconds and on exit the system time is verified
 -     again.*/
 -  test_set_step(3);
 -  {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepMilliseconds(100);
 -    test_assert_time_window(time + MS2ST(100),
 -                            time + MS2ST(100) + 1,
 -                            "out of time window");
 -  }
 -
 -  /* [1.2.4] The current system time is read then a sleep is performed
 -     for 1 second and on exit the system time is verified again.*/
 -  test_set_step(4);
 -  {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepSeconds(1);
 -    test_assert_time_window(time + S2ST(1),
 -                            time + S2ST(1) + 1,
 -                            "out of time window");
 -  }
 -
 -  /* [1.2.5] Function chThdSleepUntil() is tested with a timeline of
 -     "now" + 100 ticks.*/
 -  test_set_step(5);
 -  {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepUntil(time + 100);
 -    test_assert_time_window(time + 100,
 -                            time + 100 + 1,
 -                            "out of time window");
 +    test_print("*** CH_CFG_NUM_THREADS:        ");
 +    test_printn(CH_CFG_NUM_THREADS);
 +    test_println("");
 +    test_print("*** CH_CFG_ST_RESOLUTION:      ");
 +    test_printn(CH_CFG_ST_RESOLUTION);
 +    test_println("");
 +    test_print("*** CH_CFG_ST_FREQUENCY:       ");
 +    test_printn(CH_CFG_ST_FREQUENCY);
 +    test_println("");
 +    test_print("*** CH_CFG_ST_TIMEDELTA:       ");
 +    test_printn(CH_CFG_ST_TIMEDELTA);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_SEMAPHORES:     ");
 +    test_printn(CH_CFG_USE_SEMAPHORES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MUTEXES:        ");
 +    test_printn(CH_CFG_USE_MUTEXES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_EVENTS:         ");
 +    test_printn(CH_CFG_USE_EVENTS);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MAILBOXES:      ");
 +    test_printn(CH_CFG_USE_MAILBOXES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MEMCORE:        ");
 +    test_printn(CH_CFG_USE_MEMCORE);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_HEAP:           ");
 +    test_printn(CH_CFG_USE_HEAP);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MEMPOOLS:       ");
 +    test_printn(CH_CFG_USE_MEMPOOLS);
 +    test_println("");
 +    test_print("*** CH_DBG_STATISTICS:         ");
 +    test_printn(CH_DBG_STATISTICS);
 +    test_println("");
 +    test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
 +    test_printn(CH_DBG_SYSTEM_STATE_CHECK);
 +    test_println("");
 +    test_print("*** CH_DBG_ENABLE_CHECKS:      ");
 +    test_printn(CH_DBG_ENABLE_CHECKS);
 +    test_println("");
 +    test_print("*** CH_DBG_ENABLE_ASSERTS:     ");
 +    test_printn(CH_DBG_ENABLE_ASSERTS);
 +    test_println("");
 +    test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
 +    test_printn(CH_DBG_ENABLE_STACK_CHECK);
 +    test_println("");
    }
  }
  static const testcase_t test_001_002 = {
 -  "Thread Sleep functionality",
 +  "Kernel Settings",
    NULL,
    NULL,
    test_001_002_execute
 @@ -174,7 +166,7 @@ static const testcase_t test_001_002 = {   ****************************************************************************/
  /**
 - * @brief   Threads Functionality.
 + * @brief   Information.
   */
  const testcase_t * const test_sequence_001[] = {
    &test_001_001,
 diff --git a/test/nil/source/test/test_sequence_002.c b/test/nil/source/test/test_sequence_002.c index 1e0f41d43..9e72d707d 100644 --- a/test/nil/source/test/test_sequence_002.c +++ b/test/nil/source/test/test_sequence_002.c @@ -22,224 +22,151 @@   * @file    test_sequence_002.c
   * @brief   Test Sequence 002 code.
   *
 - * @page test_sequence_002 [2] Semaphores
 + * @page test_sequence_002 [2] Threads Functionality
   *
   * File: @ref test_sequence_002.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/NIL functionalities related to
 - * counter semaphores.
 - *
 - * <h2>Conditions</h2>
 - * This sequence is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 + * threading.
   *
   * <h2>Test Cases</h2>
   * - @subpage test_002_001
   * - @subpage test_002_002
 - * - @subpage test_002_003
   * .
   */
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 -
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
  #include "ch.h"
 -static semaphore_t sem1;
 -
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_002_001 [2.1] Semaphore primitives, no state change
 + * @page test_002_001 [2.1] System Tick Counter functionality
   *
   * <h2>Description</h2>
 - * Wait, Signal and Reset primitives are tested. The testing thread
 - * does not trigger a state change.
 + * The functionality of the API @p chVTGetSystemTimeX() is tested.
   *
   * <h2>Test Steps</h2>
 - * - [2.1.1] The function chSemWait() is invoked, after return the
 - *   counter and the returned message are tested.
 - * - [2.1.2] The function chSemSignal() is invoked, after return the
 - *   counter is tested.
 - * - [2.1.3] The function chSemReset() is invoked, after return the
 - *   counter is tested.
 + * - [2.1.1] A System Tick Counter increment is expected, the test
 + *   simply hangs if it does not happen.
   * .
   */
 -static void test_002_001_setup(void) {
 -  chSemObjectInit(&sem1, 1);
 -}
 -
 -static void test_002_001_teardown(void) {
 -  chSemReset(&sem1, 0);
 -}
 -
  static void test_002_001_execute(void) {
 -  /* [2.1.1] The function chSemWait() is invoked, after return the
 -     counter and the returned message are tested.*/
 +  /* [2.1.1] A System Tick Counter increment is expected, the test
 +     simply hangs if it does not happen.*/
    test_set_step(1);
    {
 -    msg_t msg;
 -
 -    msg = chSemWait(&sem1);
 -    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 -    test_assert(MSG_OK == msg, "wrong returned message");
 -  }
 -
 -  /* [2.1.2] The function chSemSignal() is invoked, after return the
 -     counter is tested.*/
 -  test_set_step(2);
 -  {
 -    chSemSignal(&sem1);
 -    test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
 -  }
 -
 -  /* [2.1.3] The function chSemReset() is invoked, after return the
 -     counter is tested.*/
 -  test_set_step(3);
 -  {
 -    chSemReset(&sem1, 2);
 -    test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
 +    systime_t time = chVTGetSystemTimeX();
 +    while (time == chVTGetSystemTimeX()) {
 +    }
    }
  }
  static const testcase_t test_002_001 = {
 -  "Semaphore primitives, no state change",
 -  test_002_001_setup,
 -  test_002_001_teardown,
 +  "System Tick Counter functionality",
 +  NULL,
 +  NULL,
    test_002_001_execute
  };
  /**
 - * @page test_002_002 [2.2] Semaphore primitives, with state change
 + * @page test_002_002 [2.2] Thread Sleep functionality
   *
   * <h2>Description</h2>
 - * Wait, Signal and Reset primitives are tested. The testing thread
 - * triggers a state change.
 + * The functionality of @p chThdSleep() and derivatives is tested.
   *
   * <h2>Test Steps</h2>
 - * - [2.2.1] The function chSemWait() is invoked, after return the
 - *   counter and the returned message are tested. The semaphore is
 - *   signaled by another thread.
 - * - [2.2.2] The function chSemWait() is invoked, after return the
 - *   counter and the returned message are tested. The semaphore is
 - *   reset by another thread.
 + * - [2.2.1] The current system time is read then a sleep is performed
 + *   for 100 system ticks and on exit the system time is verified
 + *   again.
 + * - [2.2.2] The current system time is read then a sleep is performed
 + *   for 100000 microseconds and on exit the system time is verified
 + *   again.
 + * - [2.2.3] The current system time is read then a sleep is performed
 + *   for 100 milliseconds and on exit the system time is verified
 + *   again.
 + * - [2.2.4] The current system time is read then a sleep is performed
 + *   for 1 second and on exit the system time is verified again.
 + * - [2.2.5] Function chThdSleepUntil() is tested with a timeline of
 + *   "now" + 100 ticks.
   * .
   */
 -static void test_002_002_setup(void) {
 -  chSemObjectInit(&gsem1, 0);
 -}
 -
 -static void test_002_002_teardown(void) {
 -  chSemReset(&gsem1, 0);
 -}
 -
  static void test_002_002_execute(void) {
 +  systime_t time;
 -  /* [2.2.1] The function chSemWait() is invoked, after return the
 -     counter and the returned message are tested. The semaphore is
 -     signaled by another thread.*/
 +  /* [2.2.1] The current system time is read then a sleep is performed
 +     for 100 system ticks and on exit the system time is verified
 +     again.*/
    test_set_step(1);
    {
 -    msg_t msg;
 -
 -    msg = chSemWait(&gsem1);
 -    test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
 -    test_assert(MSG_OK == msg, "wrong returned message");
 +    time = chVTGetSystemTimeX();
 +    chThdSleep(100);
 +    test_assert_time_window(time + 100,
 +                            time + 100 + 1,
 +                            "out of time window");
    }
 -  /* [2.2.2] The function chSemWait() is invoked, after return the
 -     counter and the returned message are tested. The semaphore is
 -     reset by another thread.*/
 +  /* [2.2.2] The current system time is read then a sleep is performed
 +     for 100000 microseconds and on exit the system time is verified
 +     again.*/
    test_set_step(2);
    {
 -    msg_t msg;
 -
 -    msg = chSemWait(&gsem2);
 -    test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
 -    test_assert(MSG_RESET == msg, "wrong returned message");
 +    time = chVTGetSystemTimeX();
 +    chThdSleepMicroseconds(100000);
 +    test_assert_time_window(time + US2ST(100000),
 +                            time + US2ST(100000) + 1,
 +                            "out of time window");
    }
 -}
 -
 -static const testcase_t test_002_002 = {
 -  "Semaphore primitives, with state change",
 -  test_002_002_setup,
 -  test_002_002_teardown,
 -  test_002_002_execute
 -};
 -
 -/**
 - * @page test_002_003 [2.3] Semaphores timeout
 - *
 - * <h2>Description</h2>
 - * Timeout on semaphores is tested.
 - *
 - * <h2>Test Steps</h2>
 - * - [2.3.1] The function chSemWaitTimeout() is invoked a first time,
 - *   after return the system time, the counter and the returned message
 - *   are tested.
 - * - [2.3.2] The function chSemWaitTimeout() is invoked again, after
 - *   return the system time, the counter and the returned message are
 - *   tested.
 - * .
 - */
 -
 -static void test_002_003_setup(void) {
 -  chSemObjectInit(&sem1, 0);
 -}
 -
 -static void test_002_003_teardown(void) {
 -  chSemReset(&sem1, 0);
 -}
 -static void test_002_003_execute(void) {
 -  systime_t time;
 -  msg_t msg;
 +  /* [2.2.3] The current system time is read then a sleep is performed
 +     for 100 milliseconds and on exit the system time is verified
 +     again.*/
 +  test_set_step(3);
 +  {
 +    time = chVTGetSystemTimeX();
 +    chThdSleepMilliseconds(100);
 +    test_assert_time_window(time + MS2ST(100),
 +                            time + MS2ST(100) + 1,
 +                            "out of time window");
 +  }
 -  /* [2.3.1] The function chSemWaitTimeout() is invoked a first time,
 -     after return the system time, the counter and the returned message
 -     are tested.*/
 -  test_set_step(1);
 +  /* [2.2.4] The current system time is read then a sleep is performed
 +     for 1 second and on exit the system time is verified again.*/
 +  test_set_step(4);
    {
      time = chVTGetSystemTimeX();
 -    msg = chSemWaitTimeout(&sem1, MS2ST(1000));
 -    test_assert_time_window(time + MS2ST(1000),
 -                            time + MS2ST(1000) + 1,
 +    chThdSleepSeconds(1);
 +    test_assert_time_window(time + S2ST(1),
 +                            time + S2ST(1) + 1,
                              "out of time window");
 -    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 -    test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
    }
 -  /* [2.3.2] The function chSemWaitTimeout() is invoked again, after
 -     return the system time, the counter and the returned message are
 -     tested.*/
 -  test_set_step(2);
 +  /* [2.2.5] Function chThdSleepUntil() is tested with a timeline of
 +     "now" + 100 ticks.*/
 +  test_set_step(5);
    {
      time = chVTGetSystemTimeX();
 -    msg = chSemWaitTimeout(&sem1, MS2ST(1000));
 -    test_assert_time_window(time + MS2ST(1000),
 -                            time + MS2ST(1000) + 1,
 +    chThdSleepUntil(time + 100);
 +    test_assert_time_window(time + 100,
 +                            time + 100 + 1,
                              "out of time window");
 -    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 -    test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
    }
  }
 -static const testcase_t test_002_003 = {
 -  "Semaphores timeout",
 -  test_002_003_setup,
 -  test_002_003_teardown,
 -  test_002_003_execute
 +static const testcase_t test_002_002 = {
 +  "Thread Sleep functionality",
 +  NULL,
 +  NULL,
 +  test_002_002_execute
  };
  /****************************************************************************
 @@ -247,13 +174,10 @@ static const testcase_t test_002_003 = {   ****************************************************************************/
  /**
 - * @brief   Semaphores.
 + * @brief   Threads Functionality.
   */
  const testcase_t * const test_sequence_002[] = {
    &test_002_001,
    &test_002_002,
 -  &test_002_003,
    NULL
  };
 -
 -#endif /* CH_CFG_USE_SEMAPHORES */
 diff --git a/test/nil/source/test/test_sequence_003.c b/test/nil/source/test/test_sequence_003.c index bf5c7941f..22e233620 100644 --- a/test/nil/source/test/test_sequence_003.c +++ b/test/nil/source/test/test_sequence_003.c @@ -22,178 +22,238 @@   * @file    test_sequence_003.c
   * @brief   Test Sequence 003 code.
   *
 - * @page test_sequence_003 [3] Suspend/Resume and Event Flags
 + * @page test_sequence_003 [3] Semaphores
   *
   * File: @ref test_sequence_003.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/NIL functionalities related to
 - * threads suspend/resume and event flags.
 + * counter semaphores.
 + *
 + * <h2>Conditions</h2>
 + * This sequence is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_003_001
   * - @subpage test_003_002
 + * - @subpage test_003_003
   * .
   */
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -static thread_reference_t tr1;
 +#include "ch.h"
 +
 +static semaphore_t sem1;
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_003_001 [3.1] Suspend and Resume functionality
 + * @page test_003_001 [3.1] Semaphore primitives, no state change
   *
   * <h2>Description</h2>
 - * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
 - * tested.
 + * Wait, Signal and Reset primitives are tested. The testing thread
 + * does not trigger a state change.
   *
   * <h2>Test Steps</h2>
 - * - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 - *   is remotely resumed with message @p MSG_OK. On return the message
 - *   and the state of the reference are tested.
 - * - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 - *   is not resumed so a timeout must occur. On return the message and
 - *   the state of the reference are tested.
 + * - [3.1.1] The function chSemWait() is invoked, after return the
 + *   counter and the returned message are tested.
 + * - [3.1.2] The function chSemSignal() is invoked, after return the
 + *   counter is tested.
 + * - [3.1.3] The function chSemReset() is invoked, after return the
 + *   counter is tested.
   * .
   */
  static void test_003_001_setup(void) {
 -  tr1 = NULL;
 +  chSemObjectInit(&sem1, 1);
 +}
 +
 +static void test_003_001_teardown(void) {
 +  chSemReset(&sem1, 0);
  }
  static void test_003_001_execute(void) {
 -  systime_t time;
 -  msg_t msg;
 -  /* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 -     is remotely resumed with message @p MSG_OK. On return the message
 -     and the state of the reference are tested.*/
 +  /* [3.1.1] The function chSemWait() is invoked, after return the
 +     counter and the returned message are tested.*/
    test_set_step(1);
    {
 -    chSysLock();
 -    msg = chThdSuspendTimeoutS(>r1, TIME_INFINITE);
 -    chSysUnlock();
 -    test_assert(NULL == gtr1, "not NULL");
 -    test_assert(MSG_OK == msg,"wrong returned message");
 +    msg_t msg;
 +
 +    msg = chSemWait(&sem1);
 +    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 +    test_assert(MSG_OK == msg, "wrong returned message");
    }
 -  /* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 -     is not resumed so a timeout must occur. On return the message and
 -     the state of the reference are tested.*/
 +  /* [3.1.2] The function chSemSignal() is invoked, after return the
 +     counter is tested.*/
    test_set_step(2);
    {
 -    chSysLock();
 -    time = chVTGetSystemTimeX();
 -    msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
 -    chSysUnlock();
 -    test_assert_time_window(time + MS2ST(1000),
 -                            time + MS2ST(1000) + 1,
 -                            "out of time window");
 -    test_assert(NULL == tr1, "not NULL");
 -    test_assert(MSG_TIMEOUT == msg, "wrong returned message");
 +    chSemSignal(&sem1);
 +    test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
 +  }
 +
 +  /* [3.1.3] The function chSemReset() is invoked, after return the
 +     counter is tested.*/
 +  test_set_step(3);
 +  {
 +    chSemReset(&sem1, 2);
 +    test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
    }
  }
  static const testcase_t test_003_001 = {
 -  "Suspend and Resume functionality",
 +  "Semaphore primitives, no state change",
    test_003_001_setup,
 -  NULL,
 +  test_003_001_teardown,
    test_003_001_execute
  };
 -#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
  /**
 - * @page test_003_002 [3.2] Events Flags functionality
 + * @page test_003_002 [3.2] Semaphore primitives, with state change
   *
   * <h2>Description</h2>
 - * Event flags functionality is tested.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_EVENTS
 - * .
 + * Wait, Signal and Reset primitives are tested. The testing thread
 + * triggers a state change.
   *
   * <h2>Test Steps</h2>
 - * - [3.2.1] A set of event flags are set on the current thread then
 - *   the function chEvtWaitAnyTimeout() is invoked, the function is
 - *   supposed to return immediately because the event flags are already
 - *   pending, after return the events mask is tested.
 - * - [3.2.2] The pending event flags mask is cleared then the function
 - *   chEvtWaitAnyTimeout() is invoked, after return the events mask is
 - *   tested. The thread is signaled by another thread.
 - * - [3.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
 - *   can wakeup the thread, the function must return because timeout.
 + * - [3.2.1] The function chSemWait() is invoked, after return the
 + *   counter and the returned message are tested. The semaphore is
 + *   signaled by another thread.
 + * - [3.2.2] The function chSemWait() is invoked, after return the
 + *   counter and the returned message are tested. The semaphore is
 + *   reset by another thread.
   * .
   */
 +static void test_003_002_setup(void) {
 +  chSemObjectInit(&gsem1, 0);
 +}
 +
 +static void test_003_002_teardown(void) {
 +  chSemReset(&gsem1, 0);
 +}
 +
  static void test_003_002_execute(void) {
 -  systime_t time;
 -  eventmask_t events;
 -  /* [3.2.1] A set of event flags are set on the current thread then
 -     the function chEvtWaitAnyTimeout() is invoked, the function is
 -     supposed to return immediately because the event flags are already
 -     pending, after return the events mask is tested.*/
 +  /* [3.2.1] The function chSemWait() is invoked, after return the
 +     counter and the returned message are tested. The semaphore is
 +     signaled by another thread.*/
    test_set_step(1);
    {
 -    time = chVTGetSystemTimeX();
 -    chEvtSignal(chThdGetSelfX(), 0x55);
 -    events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
 -    test_assert((eventmask_t)0 != events, "timed out");
 -    test_assert((eventmask_t)0x55 == events, "wrong events mask");
 +    msg_t msg;
 +
 +    msg = chSemWait(&gsem1);
 +    test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
 +    test_assert(MSG_OK == msg, "wrong returned message");
    }
 -  /* [3.2.2] The pending event flags mask is cleared then the function
 -     chEvtWaitAnyTimeout() is invoked, after return the events mask is
 -     tested. The thread is signaled by another thread.*/
 +  /* [3.2.2] The function chSemWait() is invoked, after return the
 +     counter and the returned message are tested. The semaphore is
 +     reset by another thread.*/
    test_set_step(2);
    {
 +    msg_t msg;
 +
 +    msg = chSemWait(&gsem2);
 +    test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
 +    test_assert(MSG_RESET == msg, "wrong returned message");
 +  }
 +}
 +
 +static const testcase_t test_003_002 = {
 +  "Semaphore primitives, with state change",
 +  test_003_002_setup,
 +  test_003_002_teardown,
 +  test_003_002_execute
 +};
 +
 +/**
 + * @page test_003_003 [3.3] Semaphores timeout
 + *
 + * <h2>Description</h2>
 + * Timeout on semaphores is tested.
 + *
 + * <h2>Test Steps</h2>
 + * - [3.3.1] The function chSemWaitTimeout() is invoked a first time,
 + *   after return the system time, the counter and the returned message
 + *   are tested.
 + * - [3.3.2] The function chSemWaitTimeout() is invoked again, after
 + *   return the system time, the counter and the returned message are
 + *   tested.
 + * .
 + */
 +
 +static void test_003_003_setup(void) {
 +  chSemObjectInit(&sem1, 0);
 +}
 +
 +static void test_003_003_teardown(void) {
 +  chSemReset(&sem1, 0);
 +}
 +
 +static void test_003_003_execute(void) {
 +  systime_t time;
 +  msg_t msg;
 +
 +  /* [3.3.1] The function chSemWaitTimeout() is invoked a first time,
 +     after return the system time, the counter and the returned message
 +     are tested.*/
 +  test_set_step(1);
 +  {
      time = chVTGetSystemTimeX();
 -    chThdGetSelfX()->epmask = 0;
 -    events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
 -    test_assert((eventmask_t)0 != events, "timed out");
 -    test_assert((eventmask_t)0x55 == events, "wrong events mask");
 +    msg = chSemWaitTimeout(&sem1, MS2ST(1000));
 +    test_assert_time_window(time + MS2ST(1000),
 +                            time + MS2ST(1000) + 1,
 +                            "out of time window");
 +    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 +    test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
    }
 -  /* [3.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
 -     can wakeup the thread, the function must return because timeout.*/
 -  test_set_step(3);
 +  /* [3.3.2] The function chSemWaitTimeout() is invoked again, after
 +     return the system time, the counter and the returned message are
 +     tested.*/
 +  test_set_step(2);
    {
      time = chVTGetSystemTimeX();
 -    events = chEvtWaitAnyTimeout(0, MS2ST(1000));
 +    msg = chSemWaitTimeout(&sem1, MS2ST(1000));
      test_assert_time_window(time + MS2ST(1000),
                              time + MS2ST(1000) + 1,
                              "out of time window");
 -    test_assert((eventmask_t)0 == events, "wrong events mask");
 +    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 +    test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
    }
  }
 -static const testcase_t test_003_002 = {
 -  "Events Flags functionality",
 -  NULL,
 -  NULL,
 -  test_003_002_execute
 +static const testcase_t test_003_003 = {
 +  "Semaphores timeout",
 +  test_003_003_setup,
 +  test_003_003_teardown,
 +  test_003_003_execute
  };
 -#endif /* CH_CFG_USE_EVENTS */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Suspend/Resume and Event Flags.
 + * @brief   Semaphores.
   */
  const testcase_t * const test_sequence_003[] = {
    &test_003_001,
 -#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
    &test_003_002,
 -#endif
 +  &test_003_003,
    NULL
  };
 +
 +#endif /* CH_CFG_USE_SEMAPHORES */
 diff --git a/test/nil/source/test/test_sequence_004.c b/test/nil/source/test/test_sequence_004.c index c3f3463d3..52e3e88d0 100644 --- a/test/nil/source/test/test_sequence_004.c +++ b/test/nil/source/test/test_sequence_004.c @@ -22,387 +22,178 @@   * @file    test_sequence_004.c
   * @brief   Test Sequence 004 code.
   *
 - * @page test_sequence_004 [4] Mailboxes
 + * @page test_sequence_004 [4] Suspend/Resume and Event Flags
   *
   * File: @ref test_sequence_004.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/NIL functionalities related to
 - * mailboxes.
 - *
 - * <h2>Conditions</h2>
 - * This sequence is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_MAILBOXES
 - * .
 + * threads suspend/resume and event flags.
   *
   * <h2>Test Cases</h2>
   * - @subpage test_004_001
   * - @subpage test_004_002
 - * - @subpage test_004_003
   * .
   */
 -#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
 -
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#define ALLOWED_DELAY MS2ST(5)
 -#define MB_SIZE 4
 -
 -static msg_t mb_buffer[MB_SIZE];
 -static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
 +static thread_reference_t tr1;
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_004_001 [4.1] Mailbox normal API, non-blocking tests
 + * @page test_004_001 [4.1] Suspend and Resume functionality
   *
   * <h2>Description</h2>
 - * The mailbox normal API is tested without triggering blocking
 - * conditions.
 + * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
 + * tested.
   *
   * <h2>Test Steps</h2>
 - * - [4.1.1] Testing the mailbox size.
 - * - [4.1.2] Resetting the mailbox, conditions are checked, no errors
 - *   expected.
 - * - [4.1.3] Testing the behavior of API when the mailbox is in reset
 - *   state then return in active state.
 - * - [4.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 - *   once, no errors expected.
 - * - [4.1.5] Testing intermediate conditions. Data pointers must be
 - *   aligned, semaphore counters are checked.
 - * - [4.1.6] Emptying the mailbox using chMBFetch(), no errors
 - *   expected.
 - * - [4.1.7] Posting and then fetching one more message, no errors
 - *   expected.
 - * - [4.1.8] Testing final conditions. Data pointers must be aligned to
 - *   buffer start, semaphore counters are checked.
 + * - [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 + *   is remotely resumed with message @p MSG_OK. On return the message
 + *   and the state of the reference are tested.
 + * - [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 + *   is not resumed so a timeout must occur. On return the message and
 + *   the state of the reference are tested.
   * .
   */
  static void test_004_001_setup(void) {
 -  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 -}
 -
 -static void test_004_001_teardown(void) {
 -  chMBReset(&mb1);
 +  tr1 = NULL;
  }
  static void test_004_001_execute(void) {
 -  msg_t msg1, msg2;
 -  unsigned i;
 +  systime_t time;
 +  msg_t msg;
 -  /* [4.1.1] Testing the mailbox size.*/
 +  /* [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 +     is remotely resumed with message @p MSG_OK. On return the message
 +     and the state of the reference are tested.*/
    test_set_step(1);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
 +    chSysLock();
 +    msg = chThdSuspendTimeoutS(>r1, TIME_INFINITE);
 +    chSysUnlock();
 +    test_assert(NULL == gtr1, "not NULL");
 +    test_assert(MSG_OK == msg,"wrong returned message");
    }
 -  /* [4.1.2] Resetting the mailbox, conditions are checked, no errors
 -     expected.*/
 +  /* [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 +     is not resumed so a timeout must occur. On return the message and
 +     the state of the reference are tested.*/
    test_set_step(2);
    {
 -    chMBReset(&mb1);
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 -  }
 -
 -  /* [4.1.3] Testing the behavior of API when the mailbox is in reset
 -     state then return in active state.*/
 -  test_set_step(3);
 -  {
 -    msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
 -    test_assert(msg1 == MSG_RESET, "not in reset state");
 -    msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
 -    test_assert(msg1 == MSG_RESET, "not in reset state");
 -    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -    test_assert(msg1 == MSG_RESET, "not in reset state");
 -    chMBResumeX(&mb1);
 -  }
 -
 -  /* [4.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 -     once, no errors expected.*/
 -  test_set_step(4);
 -  {
 -    for (i = 0; i < MB_SIZE - 1; i++) {
 -      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    }
 -    msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -  }
 -
 -  /* [4.1.5] Testing intermediate conditions. Data pointers must be
 -     aligned, semaphore counters are checked.*/
 -  test_set_step(5);
 -  {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 -    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
 -  }
 -
 -  /* [4.1.6] Emptying the mailbox using chMBFetch(), no errors
 -     expected.*/
 -  test_set_step(6);
 -  {
 -    for (i = 0; i < MB_SIZE; i++) {
 -      msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -      test_emit_token(msg2);
 -    }
 -    test_assert_sequence("ABCD", "wrong get sequence");
 -  }
 -
 -  /* [4.1.7] Posting and then fetching one more message, no errors
 -     expected.*/
 -  test_set_step(7);
 -  {
 -    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -  }
 -
 -  /* [4.1.8] Testing final conditions. Data pointers must be aligned to
 -     buffer start, semaphore counters are checked.*/
 -  test_set_step(8);
 -  {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    chSysLock();
 +    time = chVTGetSystemTimeX();
 +    msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
 +    chSysUnlock();
 +    test_assert_time_window(time + MS2ST(1000),
 +                            time + MS2ST(1000) + 1,
 +                            "out of time window");
 +    test_assert(NULL == tr1, "not NULL");
 +    test_assert(MSG_TIMEOUT == msg, "wrong returned message");
    }
  }
  static const testcase_t test_004_001 = {
 -  "Mailbox normal API, non-blocking tests",
 +  "Suspend and Resume functionality",
    test_004_001_setup,
 -  test_004_001_teardown,
 +  NULL,
    test_004_001_execute
  };
 +#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
  /**
 - * @page test_004_002 [4.2] Mailbox I-Class API, non-blocking tests
 + * @page test_004_002 [4.2] Events Flags functionality
   *
   * <h2>Description</h2>
 - * The mailbox I-Class API is tested without triggering blocking
 - * conditions.
 + * Event flags functionality is tested.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_EVENTS
 + * .
   *
   * <h2>Test Steps</h2>
 - * - [4.2.1] Testing the mailbox size.
 - * - [4.2.2] Resetting the mailbox, conditions are checked, no errors
 - *   expected.
 - * - [4.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 - *   once, no errors expected.
 - * - [4.2.4] Testing intermediate conditions. Data pointers must be
 - *   aligned, semaphore counters are checked.
 - * - [4.2.5] Emptying the mailbox using chMBFetchI(), no errors
 - *   expected.
 - * - [4.2.6] Posting and then fetching one more message, no errors
 - *   expected.
 - * - [4.2.7] Testing final conditions. Data pointers must be aligned to
 - *   buffer start, semaphore counters are checked.
 + * - [4.2.1] A set of event flags are set on the current thread then
 + *   the function chEvtWaitAnyTimeout() is invoked, the function is
 + *   supposed to return immediately because the event flags are already
 + *   pending, after return the events mask is tested.
 + * - [4.2.2] The pending event flags mask is cleared then the function
 + *   chEvtWaitAnyTimeout() is invoked, after return the events mask is
 + *   tested. The thread is signaled by another thread.
 + * - [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
 + *   can wakeup the thread, the function must return because timeout.
   * .
   */
 -static void test_004_002_setup(void) {
 -  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 -}
 -
 -static void test_004_002_teardown(void) {
 -  chMBReset(&mb1);
 -}
 -
  static void test_004_002_execute(void) {
 -  msg_t msg1, msg2;
 -  unsigned i;
 +  systime_t time;
 +  eventmask_t events;
 -  /* [4.2.1] Testing the mailbox size.*/
 +  /* [4.2.1] A set of event flags are set on the current thread then
 +     the function chEvtWaitAnyTimeout() is invoked, the function is
 +     supposed to return immediately because the event flags are already
 +     pending, after return the events mask is tested.*/
    test_set_step(1);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
 +    time = chVTGetSystemTimeX();
 +    chEvtSignal(chThdGetSelfX(), 0x55);
 +    events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
 +    test_assert((eventmask_t)0 != events, "timed out");
 +    test_assert((eventmask_t)0x55 == events, "wrong events mask");
    }
 -  /* [4.2.2] Resetting the mailbox, conditions are checked, no errors
 -     expected.*/
 +  /* [4.2.2] The pending event flags mask is cleared then the function
 +     chEvtWaitAnyTimeout() is invoked, after return the events mask is
 +     tested. The thread is signaled by another thread.*/
    test_set_step(2);
    {
 -    chSysLock();
 -    chMBResetI(&mb1);
 -    chSysUnlock();
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 -    chMBResumeX(&mb1);
 +    time = chVTGetSystemTimeX();
 +    chThdGetSelfX()->epmask = 0;
 +    events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
 +    test_assert((eventmask_t)0 != events, "timed out");
 +    test_assert((eventmask_t)0x55 == events, "wrong events mask");
    }
 -  /* [4.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 -     once, no errors expected.*/
 +  /* [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
 +     can wakeup the thread, the function must return because timeout.*/
    test_set_step(3);
    {
 -    for (i = 0; i < MB_SIZE - 1; i++) {
 -      chSysLock();
 -      msg1 = chMBPostI(&mb1, 'B' + i);
 -      chSysUnlock();
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    }
 -    chSysLock();
 -    msg1 = chMBPostAheadI(&mb1, 'A');
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -  }
 -
 -  /* [4.2.4] Testing intermediate conditions. Data pointers must be
 -     aligned, semaphore counters are checked.*/
 -  test_set_step(4);
 -  {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 -    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
 -  }
 -
 -  /* [4.2.5] Emptying the mailbox using chMBFetchI(), no errors
 -     expected.*/
 -  test_set_step(5);
 -  {
 -    for (i = 0; i < MB_SIZE; i++) {
 -      chSysLock();
 -      msg1 = chMBFetchI(&mb1, &msg2);
 -      chSysUnlock();
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -      test_emit_token(msg2);
 -    }
 -    test_assert_sequence("ABCD", "wrong get sequence");
 -  }
 -
 -  /* [4.2.6] Posting and then fetching one more message, no errors
 -     expected.*/
 -  test_set_step(6);
 -  {
 -    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -  }
 -
 -  /* [4.2.7] Testing final conditions. Data pointers must be aligned to
 -     buffer start, semaphore counters are checked.*/
 -  test_set_step(7);
 -  {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    time = chVTGetSystemTimeX();
 +    events = chEvtWaitAnyTimeout(0, MS2ST(1000));
 +    test_assert_time_window(time + MS2ST(1000),
 +                            time + MS2ST(1000) + 1,
 +                            "out of time window");
 +    test_assert((eventmask_t)0 == events, "wrong events mask");
    }
  }
  static const testcase_t test_004_002 = {
 -  "Mailbox I-Class API, non-blocking tests",
 -  test_004_002_setup,
 -  test_004_002_teardown,
 +  "Events Flags functionality",
 +  NULL,
 +  NULL,
    test_004_002_execute
  };
 -
 -/**
 - * @page test_004_003 [4.3] Mailbox timeouts
 - *
 - * <h2>Description</h2>
 - * The mailbox API is tested for timeouts.
 - *
 - * <h2>Test Steps</h2>
 - * - [4.3.1] Filling the mailbox.
 - * - [4.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 - *   chMBPostAheadI() timeout.
 - * - [4.3.3] Resetting the mailbox.
 - * - [4.3.4] Testing chMBFetch() and chMBFetchI() timeout.
 - * .
 - */
 -
 -static void test_004_003_setup(void) {
 -  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 -}
 -
 -static void test_004_003_teardown(void) {
 -  chMBReset(&mb1);
 -}
 -
 -static void test_004_003_execute(void) {
 -  msg_t msg1, msg2;
 -  unsigned i;
 -
 -  /* [4.3.1] Filling the mailbox.*/
 -  test_set_step(1);
 -  {
 -    for (i = 0; i < MB_SIZE; i++) {
 -      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    }
 -  }
 -
 -  /* [4.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 -     chMBPostAheadI() timeout.*/
 -  test_set_step(2);
 -  {
 -    msg1 = chMBPost(&mb1, 'X', 1);
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    chSysLock();
 -    msg1 = chMBPostI(&mb1, 'X');
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    msg1 = chMBPostAhead(&mb1, 'X', 1);
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    chSysLock();
 -    msg1 = chMBPostAheadI(&mb1, 'X');
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -  }
 -
 -  /* [4.3.3] Resetting the mailbox.*/
 -  test_set_step(3);
 -  {
 -    chMBReset(&mb1);;
 -    chMBResumeX(&mb1);
 -  }
 -
 -  /* [4.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
 -  test_set_step(4);
 -  {
 -    msg1 = chMBFetch(&mb1, &msg2, 1);
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    chSysLock();
 -    msg1 = chMBFetchI(&mb1, &msg2);
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -  }
 -}
 -
 -static const testcase_t test_004_003 = {
 -  "Mailbox timeouts",
 -  test_004_003_setup,
 -  test_004_003_teardown,
 -  test_004_003_execute
 -};
 +#endif /* CH_CFG_USE_EVENTS */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Mailboxes.
 + * @brief   Suspend/Resume and Event Flags.
   */
  const testcase_t * const test_sequence_004[] = {
    &test_004_001,
 +#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
    &test_004_002,
 -  &test_004_003,
 +#endif
    NULL
  };
 -
 -#endif /* CH_CFG_USE_MAILBOXES */
 diff --git a/test/nil/source/test/test_sequence_005.c b/test/nil/source/test/test_sequence_005.c index 3c0ef8668..70954f1d1 100644 --- a/test/nil/source/test/test_sequence_005.c +++ b/test/nil/source/test/test_sequence_005.c @@ -22,18 +22,18 @@   * @file    test_sequence_005.c
   * @brief   Test Sequence 005 code.
   *
 - * @page test_sequence_005 [5] Memory Pools
 + * @page test_sequence_005 [5] Mailboxes
   *
   * File: @ref test_sequence_005.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/NIL functionalities related to
 - * memory pools.
 + * mailboxes.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MEMPOOLS
 + * - CH_CFG_USE_MAILBOXES
   * .
   *
   * <h2>Test Cases</h2>
 @@ -43,254 +43,366 @@   * .
   */
 -#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#define MEMORY_POOL_SIZE 4
 +#define ALLOWED_DELAY MS2ST(5)
 +#define MB_SIZE 4
 -static uint32_t objects[MEMORY_POOL_SIZE];
 -static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
 -
 -#if CH_CFG_USE_SEMAPHORES
 -static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
 -#endif
 -
 -static void *null_provider(size_t size, unsigned align) {
 -
 -  (void)size;
 -  (void)align;
 -
 -  return NULL;
 -}
 +static msg_t mb_buffer[MB_SIZE];
 +static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_005_001 [5.1] Loading and emptying a memory pool
 + * @page test_005_001 [5.1] Mailbox normal API, non-blocking tests
   *
   * <h2>Description</h2>
 - * The memory pool functionality is tested by loading and emptying it,
 - * all conditions are tested.
 + * The mailbox normal API is tested without triggering blocking
 + * conditions.
   *
   * <h2>Test Steps</h2>
 - * - [5.1.1] Adding the objects to the pool using chPoolLoadArray().
 - * - [5.1.2] Emptying the pool using chPoolAlloc().
 - * - [5.1.3] Now must be empty.
 - * - [5.1.4] Adding the objects to the pool using chPoolFree().
 - * - [5.1.5] Emptying the pool using chPoolAlloc() again.
 - * - [5.1.6] Now must be empty again.
 - * - [5.1.7] Covering the case where a provider is unable to return
 - *   more memory.
 + * - [5.1.1] Testing the mailbox size.
 + * - [5.1.2] Resetting the mailbox, conditions are checked, no errors
 + *   expected.
 + * - [5.1.3] Testing the behavior of API when the mailbox is in reset
 + *   state then return in active state.
 + * - [5.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 + *   once, no errors expected.
 + * - [5.1.5] Testing intermediate conditions. Data pointers must be
 + *   aligned, semaphore counters are checked.
 + * - [5.1.6] Emptying the mailbox using chMBFetch(), no errors
 + *   expected.
 + * - [5.1.7] Posting and then fetching one more message, no errors
 + *   expected.
 + * - [5.1.8] Testing final conditions. Data pointers must be aligned to
 + *   buffer start, semaphore counters are checked.
   * .
   */
  static void test_005_001_setup(void) {
 -  chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
 +  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +}
 +
 +static void test_005_001_teardown(void) {
 +  chMBReset(&mb1);
  }
  static void test_005_001_execute(void) {
 +  msg_t msg1, msg2;
    unsigned i;
 -  /* [5.1.1] Adding the objects to the pool using chPoolLoadArray().*/
 +  /* [5.1.1] Testing the mailbox size.*/
    test_set_step(1);
    {
 -    chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
    }
 -  /* [5.1.2] Emptying the pool using chPoolAlloc().*/
 +  /* [5.1.2] Resetting the mailbox, conditions are checked, no errors
 +     expected.*/
    test_set_step(2);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
 +    chMBReset(&mb1);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
    }
 -  /* [5.1.3] Now must be empty.*/
 +  /* [5.1.3] Testing the behavior of API when the mailbox is in reset
 +     state then return in active state.*/
    test_set_step(3);
    {
 -    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
 +    msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
 +    test_assert(msg1 == MSG_RESET, "not in reset state");
 +    msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
 +    test_assert(msg1 == MSG_RESET, "not in reset state");
 +    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +    test_assert(msg1 == MSG_RESET, "not in reset state");
 +    chMBResumeX(&mb1);
    }
 -  /* [5.1.4] Adding the objects to the pool using chPoolFree().*/
 +  /* [5.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 +     once, no errors expected.*/
    test_set_step(4);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      chPoolFree(&mp1, &objects[i]);
 +    for (i = 0; i < MB_SIZE - 1; i++) {
 +      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    }
 +    msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
    }
 -  /* [5.1.5] Emptying the pool using chPoolAlloc() again.*/
 +  /* [5.1.5] Testing intermediate conditions. Data pointers must be
 +     aligned, semaphore counters are checked.*/
    test_set_step(5);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 +    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
    }
 -  /* [5.1.6] Now must be empty again.*/
 +  /* [5.1.6] Emptying the mailbox using chMBFetch(), no errors
 +     expected.*/
    test_set_step(6);
    {
 -    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
 +    for (i = 0; i < MB_SIZE; i++) {
 +      msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +      test_emit_token(msg2);
 +    }
 +    test_assert_sequence("ABCD", "wrong get sequence");
    }
 -  /* [5.1.7] Covering the case where a provider is unable to return
 -     more memory.*/
 +  /* [5.1.7] Posting and then fetching one more message, no errors
 +     expected.*/
    test_set_step(7);
    {
 -    chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
 -    test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
 +    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +  }
 +
 +  /* [5.1.8] Testing final conditions. Data pointers must be aligned to
 +     buffer start, semaphore counters are checked.*/
 +  test_set_step(8);
 +  {
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
    }
  }
  static const testcase_t test_005_001 = {
 -  "Loading and emptying a memory pool",
 +  "Mailbox normal API, non-blocking tests",
    test_005_001_setup,
 -  NULL,
 +  test_005_001_teardown,
    test_005_001_execute
  };
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /**
 - * @page test_005_002 [5.2] Loading and emptying a guarded memory pool without waiting
 + * @page test_005_002 [5.2] Mailbox I-Class API, non-blocking tests
   *
   * <h2>Description</h2>
 - * The memory pool functionality is tested by loading and emptying it,
 - * all conditions are tested.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 + * The mailbox I-Class API is tested without triggering blocking
 + * conditions.
   *
   * <h2>Test Steps</h2>
 - * - [5.2.1] Adding the objects to the pool using
 - *   chGuardedPoolLoadArray().
 - * - [5.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
 - * - [5.2.3] Now must be empty.
 - * - [5.2.4] Adding the objects to the pool using chGuardedPoolFree().
 - * - [5.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
 - * - [5.2.6] Now must be empty again.
 + * - [5.2.1] Testing the mailbox size.
 + * - [5.2.2] Resetting the mailbox, conditions are checked, no errors
 + *   expected.
 + * - [5.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 + *   once, no errors expected.
 + * - [5.2.4] Testing intermediate conditions. Data pointers must be
 + *   aligned, semaphore counters are checked.
 + * - [5.2.5] Emptying the mailbox using chMBFetchI(), no errors
 + *   expected.
 + * - [5.2.6] Posting and then fetching one more message, no errors
 + *   expected.
 + * - [5.2.7] Testing final conditions. Data pointers must be aligned to
 + *   buffer start, semaphore counters are checked.
   * .
   */
  static void test_005_002_setup(void) {
 -  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +}
 +
 +static void test_005_002_teardown(void) {
 +  chMBReset(&mb1);
  }
  static void test_005_002_execute(void) {
 +  msg_t msg1, msg2;
    unsigned i;
 -  /* [5.2.1] Adding the objects to the pool using
 -     chGuardedPoolLoadArray().*/
 +  /* [5.2.1] Testing the mailbox size.*/
    test_set_step(1);
    {
 -    chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
    }
 -  /* [5.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
 +  /* [5.2.2] Resetting the mailbox, conditions are checked, no errors
 +     expected.*/
    test_set_step(2);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +    chSysLock();
 +    chMBResetI(&mb1);
 +    chSysUnlock();
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    chMBResumeX(&mb1);
    }
 -  /* [5.2.3] Now must be empty.*/
 +  /* [5.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 +     once, no errors expected.*/
    test_set_step(3);
    {
 -    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
 +    for (i = 0; i < MB_SIZE - 1; i++) {
 +      chSysLock();
 +      msg1 = chMBPostI(&mb1, 'B' + i);
 +      chSysUnlock();
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    }
 +    chSysLock();
 +    msg1 = chMBPostAheadI(&mb1, 'A');
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
    }
 -  /* [5.2.4] Adding the objects to the pool using
 -     chGuardedPoolFree().*/
 +  /* [5.2.4] Testing intermediate conditions. Data pointers must be
 +     aligned, semaphore counters are checked.*/
    test_set_step(4);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      chGuardedPoolFree(&gmp1, &objects[i]);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 +    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
    }
 -  /* [5.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
 -     again.*/
 +  /* [5.2.5] Emptying the mailbox using chMBFetchI(), no errors
 +     expected.*/
    test_set_step(5);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +    for (i = 0; i < MB_SIZE; i++) {
 +      chSysLock();
 +      msg1 = chMBFetchI(&mb1, &msg2);
 +      chSysUnlock();
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +      test_emit_token(msg2);
 +    }
 +    test_assert_sequence("ABCD", "wrong get sequence");
    }
 -  /* [5.2.6] Now must be empty again.*/
 +  /* [5.2.6] Posting and then fetching one more message, no errors
 +     expected.*/
    test_set_step(6);
    {
 -    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
 +    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +  }
 +
 +  /* [5.2.7] Testing final conditions. Data pointers must be aligned to
 +     buffer start, semaphore counters are checked.*/
 +  test_set_step(7);
 +  {
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
    }
  }
  static const testcase_t test_005_002 = {
 -  "Loading and emptying a guarded memory pool without waiting",
 +  "Mailbox I-Class API, non-blocking tests",
    test_005_002_setup,
 -  NULL,
 +  test_005_002_teardown,
    test_005_002_execute
  };
 -#endif /* CH_CFG_USE_SEMAPHORES */
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /**
 - * @page test_005_003 [5.3] Guarded Memory Pools timeout
 + * @page test_005_003 [5.3] Mailbox timeouts
   *
   * <h2>Description</h2>
 - * The timeout features for the Guarded Memory Pools is tested.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 + * The mailbox API is tested for timeouts.
   *
   * <h2>Test Steps</h2>
 - * - [5.3.1] Trying to allocate with 100mS timeout, must fail because
 - *   the pool is empty.
 + * - [5.3.1] Filling the mailbox.
 + * - [5.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 + *   chMBPostAheadI() timeout.
 + * - [5.3.3] Resetting the mailbox.
 + * - [5.3.4] Testing chMBFetch() and chMBFetchI() timeout.
   * .
   */
  static void test_005_003_setup(void) {
 -  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +}
 +
 +static void test_005_003_teardown(void) {
 +  chMBReset(&mb1);
  }
  static void test_005_003_execute(void) {
 +  msg_t msg1, msg2;
 +  unsigned i;
 -  /* [5.3.1] Trying to allocate with 100mS timeout, must fail because
 -     the pool is empty.*/
 +  /* [5.3.1] Filling the mailbox.*/
    test_set_step(1);
    {
 -    test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
 +    for (i = 0; i < MB_SIZE; i++) {
 +      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    }
 +  }
 +
 +  /* [5.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 +     chMBPostAheadI() timeout.*/
 +  test_set_step(2);
 +  {
 +    msg1 = chMBPost(&mb1, 'X', 1);
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chSysLock();
 +    msg1 = chMBPostI(&mb1, 'X');
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    msg1 = chMBPostAhead(&mb1, 'X', 1);
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chSysLock();
 +    msg1 = chMBPostAheadI(&mb1, 'X');
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +  }
 +
 +  /* [5.3.3] Resetting the mailbox.*/
 +  test_set_step(3);
 +  {
 +    chMBReset(&mb1);;
 +    chMBResumeX(&mb1);
 +  }
 +
 +  /* [5.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
 +  test_set_step(4);
 +  {
 +    msg1 = chMBFetch(&mb1, &msg2, 1);
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chSysLock();
 +    msg1 = chMBFetchI(&mb1, &msg2);
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
    }
  }
  static const testcase_t test_005_003 = {
 -  "Guarded Memory Pools timeout",
 +  "Mailbox timeouts",
    test_005_003_setup,
 -  NULL,
 +  test_005_003_teardown,
    test_005_003_execute
  };
 -#endif /* CH_CFG_USE_SEMAPHORES */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Memory Pools.
 + * @brief   Mailboxes.
   */
  const testcase_t * const test_sequence_005[] = {
    &test_005_001,
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    &test_005_002,
 -#endif
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    &test_005_003,
 -#endif
    NULL
  };
 -#endif /* CH_CFG_USE_MEMPOOLS */
 +#endif /* CH_CFG_USE_MAILBOXES */
 diff --git a/test/nil/source/test/test_sequence_006.c b/test/nil/source/test/test_sequence_006.c index ba3e8cbf9..dad464e6c 100644 --- a/test/nil/source/test/test_sequence_006.c +++ b/test/nil/source/test/test_sequence_006.c @@ -22,252 +22,275 @@   * @file    test_sequence_006.c
   * @brief   Test Sequence 006 code.
   *
 - * @page test_sequence_006 [6] Memory Heaps
 + * @page test_sequence_006 [6] Memory Pools
   *
   * File: @ref test_sequence_006.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/NIL functionalities related to
 - * memory heaps.
 + * memory pools.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_HEAP
 + * - CH_CFG_USE_MEMPOOLS
   * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_006_001
   * - @subpage test_006_002
 + * - @subpage test_006_003
   * .
   */
 -#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#define ALLOC_SIZE 16
 -#define HEAP_SIZE (ALLOC_SIZE * 8)
 +#define MEMORY_POOL_SIZE 4
 -static memory_heap_t test_heap;
 -static CH_HEAP_AREA(myheap, HEAP_SIZE);
 +static uint32_t objects[MEMORY_POOL_SIZE];
 +static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
 +
 +#if CH_CFG_USE_SEMAPHORES
 +static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
 +#endif
 +
 +static void *null_provider(size_t size, unsigned align) {
 +
 +  (void)size;
 +  (void)align;
 +
 +  return NULL;
 +}
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_006_001 [6.1] Allocation and fragmentation
 + * @page test_006_001 [6.1] Loading and emptying a memory pool
   *
   * <h2>Description</h2>
 - * Series of allocations/deallocations are performed in carefully
 - * designed sequences in order to stimulate all the possible code paths
 - * inside the allocator. The test expects to find the heap back to the
 - * initial status after each sequence.
 + * The memory pool functionality is tested by loading and emptying it,
 + * all conditions are tested.
   *
   * <h2>Test Steps</h2>
 - * - [6.1.1] Testing initial conditions, the heap must not be
 - *   fragmented and one free block present.
 - * - [6.1.2] Trying to allocate an block bigger than available space,
 - *   an error is expected.
 - * - [6.1.3] Single block allocation using chHeapAlloc() then the block
 - *   is freed using chHeapFree(), must not fail.
 - * - [6.1.4] Using chHeapStatus() to assess the heap state. There must
 - *   be at least one free block of sufficient size.
 - * - [6.1.5] Allocating then freeing in the same order.
 - * - [6.1.6] Allocating then freeing in reverse order.
 - * - [6.1.7] Small fragments handling. Checking the behavior when
 - *   allocating blocks with size not multiple of alignment unit.
 - * - [6.1.8] Skipping a fragment, the first fragment in the list is too
 - *   small so the allocator must pick the second one.
 - * - [6.1.9] Allocating the whole available space.
 - * - [6.1.10] Testing final conditions. The heap geometry must be the
 - *   same than the one registered at beginning.
 + * - [6.1.1] Adding the objects to the pool using chPoolLoadArray().
 + * - [6.1.2] Emptying the pool using chPoolAlloc().
 + * - [6.1.3] Now must be empty.
 + * - [6.1.4] Adding the objects to the pool using chPoolFree().
 + * - [6.1.5] Emptying the pool using chPoolAlloc() again.
 + * - [6.1.6] Now must be empty again.
 + * - [6.1.7] Covering the case where a provider is unable to return
 + *   more memory.
   * .
   */
  static void test_006_001_setup(void) {
 -  chHeapObjectInit(&test_heap, myheap, sizeof(myheap));
 +  chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
  }
  static void test_006_001_execute(void) {
 -  void *p1, *p2, *p3;
 -  size_t n, sz;
 +  unsigned i;
 -  /* [6.1.1] Testing initial conditions, the heap must not be
 -     fragmented and one free block present.*/
 +  /* [6.1.1] Adding the objects to the pool using chPoolLoadArray().*/
    test_set_step(1);
    {
 -    test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
 +    chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
    }
 -  /* [6.1.2] Trying to allocate an block bigger than available space,
 -     an error is expected.*/
 +  /* [6.1.2] Emptying the pool using chPoolAlloc().*/
    test_set_step(2);
    {
 -    p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2);
 -    test_assert(p1 == NULL, "allocation not failed");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
    }
 -  /* [6.1.3] Single block allocation using chHeapAlloc() then the block
 -     is freed using chHeapFree(), must not fail.*/
 +  /* [6.1.3] Now must be empty.*/
    test_set_step(3);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    test_assert(p1 != NULL, "allocation failed");
 -    chHeapFree(p1);
 +    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
    }
 -  /* [6.1.4] Using chHeapStatus() to assess the heap state. There must
 -     be at least one free block of sufficient size.*/
 +  /* [6.1.4] Adding the objects to the pool using chPoolFree().*/
    test_set_step(4);
    {
 -    size_t total_size, largest_size;
 -
 -    n = chHeapStatus(&test_heap, &total_size, &largest_size);
 -    test_assert(n == 1, "missing free block");
 -    test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
 -    test_assert(total_size == largest_size, "unexpected heap state");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      chPoolFree(&mp1, &objects[i]);
    }
 -  /* [6.1.5] Allocating then freeing in the same order.*/
 +  /* [6.1.5] Emptying the pool using chPoolAlloc() again.*/
    test_set_step(5);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p1);                                 /* Does not merge.*/
 -    chHeapFree(p2);                                 /* Merges backward.*/
 -    chHeapFree(p3);                                 /* Merges both sides.*/
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
    }
 -  /* [6.1.6] Allocating then freeing in reverse order.*/
 +  /* [6.1.6] Now must be empty again.*/
    test_set_step(6);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p3);                                 /* Merges forward.*/
 -    chHeapFree(p2);                                 /* Merges forward.*/
 -    chHeapFree(p1);                                 /* Merges forward.*/
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
    }
 -  /* [6.1.7] Small fragments handling. Checking the behavior when
 -     allocating blocks with size not multiple of alignment unit.*/
 +  /* [6.1.7] Covering the case where a provider is unable to return
 +     more memory.*/
    test_set_step(7);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p1);
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    /* Note, the first situation happens when the alignment size is smaller
 -       than the header size, the second in the other cases.*/
 -    test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
 -                (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
 -    chHeapFree(p2);
 -    chHeapFree(p1);
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 -  }
 -
 -  /* [6.1.8] Skipping a fragment, the first fragment in the list is too
 -     small so the allocator must pick the second one.*/
 -  test_set_step(8);
 -  {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p1);
 -    test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
 -    chHeapFree(p1);
 -    chHeapFree(p2);
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 -  }
 -
 -  /* [6.1.9] Allocating the whole available space.*/
 -  test_set_step(9);
 -  {
 -    (void)chHeapStatus(&test_heap, &n, NULL);
 -    p1 = chHeapAlloc(&test_heap, n);
 -    test_assert(p1 != NULL, "allocation failed");
 -    test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
 -    chHeapFree(p1);
 -  }
 -
 -  /* [6.1.10] Testing final conditions. The heap geometry must be the
 -     same than the one registered at beginning.*/
 -  test_set_step(10);
 -  {
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 -    test_assert(n == sz, "size changed");
 +    chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
 +    test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
    }
  }
  static const testcase_t test_006_001 = {
 -  "Allocation and fragmentation",
 +  "Loading and emptying a memory pool",
    test_006_001_setup,
    NULL,
    test_006_001_execute
  };
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /**
 - * @page test_006_002 [6.2] Default Heap
 + * @page test_006_002 [6.2] Loading and emptying a guarded memory pool without waiting
   *
   * <h2>Description</h2>
 - * The default heap is pre-allocated in the system. We test base
 - * functionality.
 + * The memory pool functionality is tested by loading and emptying it,
 + * all conditions are tested.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
   *
   * <h2>Test Steps</h2>
 - * - [6.2.1] Single block allocation using chHeapAlloc() then the block
 - *   is freed using chHeapFree(), must not fail.
 - * - [6.2.2] Testing allocation failure.
 + * - [6.2.1] Adding the objects to the pool using
 + *   chGuardedPoolLoadArray().
 + * - [6.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
 + * - [6.2.3] Now must be empty.
 + * - [6.2.4] Adding the objects to the pool using chGuardedPoolFree().
 + * - [6.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
 + * - [6.2.6] Now must be empty again.
   * .
   */
 +static void test_006_002_setup(void) {
 +  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +}
 +
  static void test_006_002_execute(void) {
 -  void *p1;
 -  size_t total_size, largest_size;
 +  unsigned i;
 -  /* [6.2.1] Single block allocation using chHeapAlloc() then the block
 -     is freed using chHeapFree(), must not fail.*/
 +  /* [6.2.1] Adding the objects to the pool using
 +     chGuardedPoolLoadArray().*/
    test_set_step(1);
    {
 -    (void)chHeapStatus(NULL, &total_size, &largest_size);
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    test_assert(p1 != NULL, "allocation failed");
 -    chHeapFree(p1);
 +    chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
    }
 -  /* [6.2.2] Testing allocation failure.*/
 +  /* [6.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
    test_set_step(2);
    {
 -    p1 = chHeapAlloc(NULL, (size_t)-256);
 -    test_assert(p1 == NULL, "allocation not failed");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +  }
 +
 +  /* [6.2.3] Now must be empty.*/
 +  test_set_step(3);
 +  {
 +    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
 +  }
 +
 +  /* [6.2.4] Adding the objects to the pool using
 +     chGuardedPoolFree().*/
 +  test_set_step(4);
 +  {
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      chGuardedPoolFree(&gmp1, &objects[i]);
 +  }
 +
 +  /* [6.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
 +     again.*/
 +  test_set_step(5);
 +  {
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +  }
 +
 +  /* [6.2.6] Now must be empty again.*/
 +  test_set_step(6);
 +  {
 +    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
    }
  }
  static const testcase_t test_006_002 = {
 -  "Default Heap",
 -  NULL,
 +  "Loading and emptying a guarded memory pool without waiting",
 +  test_006_002_setup,
    NULL,
    test_006_002_execute
  };
 +#endif /* CH_CFG_USE_SEMAPHORES */
 +
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_003 [6.3] Guarded Memory Pools timeout
 + *
 + * <h2>Description</h2>
 + * The timeout features for the Guarded Memory Pools is tested.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.3.1] Trying to allocate with 100mS timeout, must fail because
 + *   the pool is empty.
 + * .
 + */
 +
 +static void test_006_003_setup(void) {
 +  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +}
 +
 +static void test_006_003_execute(void) {
 +
 +  /* [6.3.1] Trying to allocate with 100mS timeout, must fail because
 +     the pool is empty.*/
 +  test_set_step(1);
 +  {
 +    test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
 +  }
 +}
 +
 +static const testcase_t test_006_003 = {
 +  "Guarded Memory Pools timeout",
 +  test_006_003_setup,
 +  NULL,
 +  test_006_003_execute
 +};
 +#endif /* CH_CFG_USE_SEMAPHORES */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Memory Heaps.
 + * @brief   Memory Pools.
   */
  const testcase_t * const test_sequence_006[] = {
    &test_006_001,
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    &test_006_002,
 +#endif
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +  &test_006_003,
 +#endif
    NULL
  };
 -#endif /* CH_CFG_USE_HEAP */
 +#endif /* CH_CFG_USE_MEMPOOLS */
 diff --git a/test/nil/source/test/test_sequence_007.c b/test/nil/source/test/test_sequence_007.c new file mode 100644 index 000000000..4cd0c804e --- /dev/null +++ b/test/nil/source/test/test_sequence_007.c @@ -0,0 +1,273 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
 +
 +    Licensed under the Apache License, Version 2.0 (the "License");
 +    you may not use this file except in compliance with the License.
 +    You may obtain a copy of the License at
 +
 +        http://www.apache.org/licenses/LICENSE-2.0
 +
 +    Unless required by applicable law or agreed to in writing, software
 +    distributed under the License is distributed on an "AS IS" BASIS,
 +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +    See the License for the specific language governing permissions and
 +    limitations under the License.
 +*/
 +
 +#include "hal.h"
 +#include "ch_test.h"
 +#include "test_root.h"
 +
 +/**
 + * @file    test_sequence_007.c
 + * @brief   Test Sequence 007 code.
 + *
 + * @page test_sequence_007 [7] Memory Heaps
 + *
 + * File: @ref test_sequence_007.c
 + *
 + * <h2>Description</h2>
 + * This sequence tests the ChibiOS/NIL functionalities related to
 + * memory heaps.
 + *
 + * <h2>Conditions</h2>
 + * This sequence is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_HEAP
 + * .
 + *
 + * <h2>Test Cases</h2>
 + * - @subpage test_007_001
 + * - @subpage test_007_002
 + * .
 + */
 +
 +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
 +
 +/****************************************************************************
 + * Shared code.
 + ****************************************************************************/
 +
 +#define ALLOC_SIZE 16
 +#define HEAP_SIZE (ALLOC_SIZE * 8)
 +
 +static memory_heap_t test_heap;
 +static CH_HEAP_AREA(myheap, HEAP_SIZE);
 +
 +/****************************************************************************
 + * Test cases.
 + ****************************************************************************/
 +
 +/**
 + * @page test_007_001 [7.1] Allocation and fragmentation
 + *
 + * <h2>Description</h2>
 + * Series of allocations/deallocations are performed in carefully
 + * designed sequences in order to stimulate all the possible code paths
 + * inside the allocator. The test expects to find the heap back to the
 + * initial status after each sequence.
 + *
 + * <h2>Test Steps</h2>
 + * - [7.1.1] Testing initial conditions, the heap must not be
 + *   fragmented and one free block present.
 + * - [7.1.2] Trying to allocate an block bigger than available space,
 + *   an error is expected.
 + * - [7.1.3] Single block allocation using chHeapAlloc() then the block
 + *   is freed using chHeapFree(), must not fail.
 + * - [7.1.4] Using chHeapStatus() to assess the heap state. There must
 + *   be at least one free block of sufficient size.
 + * - [7.1.5] Allocating then freeing in the same order.
 + * - [7.1.6] Allocating then freeing in reverse order.
 + * - [7.1.7] Small fragments handling. Checking the behavior when
 + *   allocating blocks with size not multiple of alignment unit.
 + * - [7.1.8] Skipping a fragment, the first fragment in the list is too
 + *   small so the allocator must pick the second one.
 + * - [7.1.9] Allocating the whole available space.
 + * - [7.1.10] Testing final conditions. The heap geometry must be the
 + *   same than the one registered at beginning.
 + * .
 + */
 +
 +static void test_007_001_setup(void) {
 +  chHeapObjectInit(&test_heap, myheap, sizeof(myheap));
 +}
 +
 +static void test_007_001_execute(void) {
 +  void *p1, *p2, *p3;
 +  size_t n, sz;
 +
 +  /* [7.1.1] Testing initial conditions, the heap must not be
 +     fragmented and one free block present.*/
 +  test_set_step(1);
 +  {
 +    test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [7.1.2] Trying to allocate an block bigger than available space,
 +     an error is expected.*/
 +  test_set_step(2);
 +  {
 +    p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2);
 +    test_assert(p1 == NULL, "allocation not failed");
 +  }
 +
 +  /* [7.1.3] Single block allocation using chHeapAlloc() then the block
 +     is freed using chHeapFree(), must not fail.*/
 +  test_set_step(3);
 +  {
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    test_assert(p1 != NULL, "allocation failed");
 +    chHeapFree(p1);
 +  }
 +
 +  /* [7.1.4] Using chHeapStatus() to assess the heap state. There must
 +     be at least one free block of sufficient size.*/
 +  test_set_step(4);
 +  {
 +    size_t total_size, largest_size;
 +
 +    n = chHeapStatus(&test_heap, &total_size, &largest_size);
 +    test_assert(n == 1, "missing free block");
 +    test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
 +    test_assert(total_size == largest_size, "unexpected heap state");
 +  }
 +
 +  /* [7.1.5] Allocating then freeing in the same order.*/
 +  test_set_step(5);
 +  {
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p1);                                 /* Does not merge.*/
 +    chHeapFree(p2);                                 /* Merges backward.*/
 +    chHeapFree(p3);                                 /* Merges both sides.*/
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [7.1.6] Allocating then freeing in reverse order.*/
 +  test_set_step(6);
 +  {
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p3);                                 /* Merges forward.*/
 +    chHeapFree(p2);                                 /* Merges forward.*/
 +    chHeapFree(p1);                                 /* Merges forward.*/
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [7.1.7] Small fragments handling. Checking the behavior when
 +     allocating blocks with size not multiple of alignment unit.*/
 +  test_set_step(7);
 +  {
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p1);
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    /* Note, the first situation happens when the alignment size is smaller
 +       than the header size, the second in the other cases.*/
 +    test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
 +                (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
 +    chHeapFree(p2);
 +    chHeapFree(p1);
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [7.1.8] Skipping a fragment, the first fragment in the list is too
 +     small so the allocator must pick the second one.*/
 +  test_set_step(8);
 +  {
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p1);
 +    test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
 +    chHeapFree(p1);
 +    chHeapFree(p2);
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [7.1.9] Allocating the whole available space.*/
 +  test_set_step(9);
 +  {
 +    (void)chHeapStatus(&test_heap, &n, NULL);
 +    p1 = chHeapAlloc(&test_heap, n);
 +    test_assert(p1 != NULL, "allocation failed");
 +    test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
 +    chHeapFree(p1);
 +  }
 +
 +  /* [7.1.10] Testing final conditions. The heap geometry must be the
 +     same than the one registered at beginning.*/
 +  test_set_step(10);
 +  {
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +    test_assert(n == sz, "size changed");
 +  }
 +}
 +
 +static const testcase_t test_007_001 = {
 +  "Allocation and fragmentation",
 +  test_007_001_setup,
 +  NULL,
 +  test_007_001_execute
 +};
 +
 +/**
 + * @page test_007_002 [7.2] Default Heap
 + *
 + * <h2>Description</h2>
 + * The default heap is pre-allocated in the system. We test base
 + * functionality.
 + *
 + * <h2>Test Steps</h2>
 + * - [7.2.1] Single block allocation using chHeapAlloc() then the block
 + *   is freed using chHeapFree(), must not fail.
 + * - [7.2.2] Testing allocation failure.
 + * .
 + */
 +
 +static void test_007_002_execute(void) {
 +  void *p1;
 +  size_t total_size, largest_size;
 +
 +  /* [7.2.1] Single block allocation using chHeapAlloc() then the block
 +     is freed using chHeapFree(), must not fail.*/
 +  test_set_step(1);
 +  {
 +    (void)chHeapStatus(NULL, &total_size, &largest_size);
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    test_assert(p1 != NULL, "allocation failed");
 +    chHeapFree(p1);
 +  }
 +
 +  /* [7.2.2] Testing allocation failure.*/
 +  test_set_step(2);
 +  {
 +    p1 = chHeapAlloc(NULL, (size_t)-256);
 +    test_assert(p1 == NULL, "allocation not failed");
 +  }
 +}
 +
 +static const testcase_t test_007_002 = {
 +  "Default Heap",
 +  NULL,
 +  NULL,
 +  test_007_002_execute
 +};
 +
 +/****************************************************************************
 + * Exported data.
 + ****************************************************************************/
 +
 +/**
 + * @brief   Memory Heaps.
 + */
 +const testcase_t * const test_sequence_007[] = {
 +  &test_007_001,
 +  &test_007_002,
 +  NULL
 +};
 +
 +#endif /* CH_CFG_USE_HEAP */
 diff --git a/test/nil/source/test/test_sequence_007.h b/test/nil/source/test/test_sequence_007.h new file mode 100644 index 000000000..18b68a556 --- /dev/null +++ b/test/nil/source/test/test_sequence_007.h @@ -0,0 +1,27 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
 +
 +    Licensed under the Apache License, Version 2.0 (the "License");
 +    you may not use this file except in compliance with the License.
 +    You may obtain a copy of the License at
 +
 +        http://www.apache.org/licenses/LICENSE-2.0
 +
 +    Unless required by applicable law or agreed to in writing, software
 +    distributed under the License is distributed on an "AS IS" BASIS,
 +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +    See the License for the specific language governing permissions and
 +    limitations under the License.
 +*/
 +
 +/**
 + * @file    test_sequence_007.h
 + * @brief   Test Sequence 007 header.
 + */
 +
 +#ifndef TEST_SEQUENCE_007_H
 +#define TEST_SEQUENCE_007_H
 +
 +extern const testcase_t * const test_sequence_007[];
 +
 +#endif /* TEST_SEQUENCE_007_H */
 diff --git a/test/nil/test.mk b/test/nil/test.mk index 92c30be25..ac60ee95a 100644 --- a/test/nil/test.mk +++ b/test/nil/test.mk @@ -6,7 +6,8 @@ TESTSRC = ${CHIBIOS}/test/lib/ch_test.c \            ${CHIBIOS}/test/nil/source/test/test_sequence_003.c \
            ${CHIBIOS}/test/nil/source/test/test_sequence_004.c \
            ${CHIBIOS}/test/nil/source/test/test_sequence_005.c \
 -          ${CHIBIOS}/test/nil/source/test/test_sequence_006.c
 +          ${CHIBIOS}/test/nil/source/test/test_sequence_006.c\
 +          ${CHIBIOS}/test/nil/source/test/test_sequence_007.c
  # Required include directories
  TESTINC = ${CHIBIOS}/test/lib \
 diff --git a/test/rt/configuration.xml b/test/rt/configuration.xml index 49305faac..dcbdc233d 100644 --- a/test/rt/configuration.xml +++ b/test/rt/configuration.xml @@ -131,6 +131,210 @@ systime_t test_wait_tick(void) {                <value>Internal Tests</value>
              </type>
              <brief>
 +              <value>Information.</value>
 +            </brief>
 +            <description>
 +              <value>This sequence reports configuration and version information about the RT kernel.</value>
 +            </description>
 +            <condition>
 +              <value />
 +            </condition>
 +            <shared_code>
 +              <value><![CDATA[#include "ch.h"]]></value>
 +            </shared_code>
 +            <cases>
 +              <case>
 +                <brief>
 +                  <value>Kernel Info.</value>
 +                </brief>
 +                <description>
 +                  <value>The version numbers are reported.</value>
 +                </description>
 +                <condition>
 +                  <value />
 +                </condition>
 +                <various_code>
 +                  <setup_code>
 +                    <value />
 +                  </setup_code>
 +                  <teardown_code>
 +                    <value />
 +                  </teardown_code>
 +                  <local_variables>
 +                    <value />
 +                  </local_variables>
 +                </various_code>
 +                <steps>
 +                  <step>
 +                    <description>
 +                      <value>Prints the version string.</value>
 +                    </description>
 +                    <tags>
 +                      <value />
 +                    </tags>
 +                    <code>
 +                      <value><![CDATA[test_println("*** Product:                   ChibiOS/RT");
 +test_print("*** Stable Flag:               ");
 +test_printn(CH_KERNEL_STABLE);
 +test_println("");
 +test_print("*** Version String:            ");
 +test_println(CH_KERNEL_VERSION);
 +test_print("*** Major Number:              ");
 +test_printn(CH_KERNEL_MAJOR);
 +test_println("");
 +test_print("*** Minor Number:              ");
 +test_printn(CH_KERNEL_MINOR);
 +test_println("");
 +test_print("*** Patch Number:              ");
 +test_printn(CH_KERNEL_PATCH);
 +test_println("");]]></value>
 +                    </code>
 +                  </step>
 +                </steps>
 +              </case>
 +              <case>
 +                <brief>
 +                  <value>Kernel Settings.</value>
 +                </brief>
 +                <description>
 +                  <value>The static kernel settings are reported.</value>
 +                </description>
 +                <condition>
 +                  <value />
 +                </condition>
 +                <various_code>
 +                  <setup_code>
 +                    <value />
 +                  </setup_code>
 +                  <teardown_code>
 +                    <value />
 +                  </teardown_code>
 +                  <local_variables>
 +                    <value />
 +                  </local_variables>
 +                </various_code>
 +                <steps>
 +                  <step>
 +                    <description>
 +                      <value>Prints the configuration options settings.</value>
 +                    </description>
 +                    <tags>
 +                      <value />
 +                    </tags>
 +                    <code>
 +                      <value><![CDATA[test_print("*** CH_CFG_ST_RESOLUTION:      ");
 +test_printn(CH_CFG_ST_RESOLUTION);
 +test_println("");
 +test_print("*** CH_CFG_ST_FREQUENCY:       ");
 +test_printn(CH_CFG_ST_FREQUENCY);
 +test_println("");
 +test_print("*** CH_CFG_ST_TIMEDELTA:       ");
 +test_printn(CH_CFG_ST_TIMEDELTA);
 +test_println("");
 +test_print("*** CH_CFG_TIME_QUANTUM:       ");
 +test_printn(CH_CFG_TIME_QUANTUM);
 +test_println("");
 +test_print("*** CH_CFG_MEMCORE_SIZE:       ");
 +test_printn(CH_CFG_MEMCORE_SIZE);
 +test_println("");
 +test_print("*** CH_CFG_NO_IDLE_THREAD:     ");
 +test_printn(CH_CFG_NO_IDLE_THREAD);
 +test_println("");
 +test_print("*** CH_CFG_OPTIMIZE_SPEED:     ");
 +test_printn(CH_CFG_OPTIMIZE_SPEED);
 +test_println("");
 +test_print("*** CH_CFG_USE_TM:             ");
 +test_printn(CH_CFG_USE_TM);
 +test_println("");
 +test_print("*** CH_CFG_USE_REGISTRY:       ");
 +test_printn(CH_CFG_USE_REGISTRY);
 +test_println("");
 +test_print("*** CH_CFG_USE_WAITEXIT:       ");
 +test_printn(CH_CFG_USE_WAITEXIT);
 +test_println("");
 +test_print("*** CH_CFG_USE_SEMAPHORES:     ");
 +test_printn(CH_CFG_USE_SEMAPHORES);
 +test_println("");
 +test_print("*** CH_CFG_USE_SEMAPHORES_PRI: ");
 +test_printn(CH_CFG_USE_SEMAPHORES_PRIORITY);
 +test_println("");
 +test_print("*** CH_CFG_USE_MUTEXES:        ");
 +test_printn(CH_CFG_USE_MUTEXES);
 +test_println("");
 +test_print("*** CH_CFG_USE_MUTEXES_RECURS: ");
 +test_printn(CH_CFG_USE_MUTEXES_RECURSIVE);
 +test_println("");
 +test_print("*** CH_CFG_USE_CONDVARS:       ");
 +test_printn(CH_CFG_USE_CONDVARS);
 +test_println("");
 +test_print("*** CH_CFG_USE_CONDVARS_TIMEO: ");
 +test_printn(CH_CFG_USE_CONDVARS_TIMEOUT);
 +test_println("");
 +test_print("*** CH_CFG_USE_EVENTS:         ");
 +test_printn(CH_CFG_USE_EVENTS);
 +test_println("");
 +test_print("*** CH_CFG_USE_EVENTS_TIMEOUT: ");
 +test_printn(CH_CFG_USE_EVENTS_TIMEOUT);
 +test_println("");
 +test_print("*** CH_CFG_USE_MESSAGES:       ");
 +test_printn(CH_CFG_USE_MESSAGES);
 +test_println("");
 +test_print("*** CH_CFG_USE_MESSAGES_PRI:   ");
 +test_printn(CH_CFG_USE_MESSAGES_PRIORITY);
 +test_println("");
 +test_print("*** CH_CFG_USE_MAILBOXES:      ");
 +test_printn(CH_CFG_USE_MAILBOXES);
 +test_println("");
 +test_print("*** CH_CFG_USE_MEMCORE:        ");
 +test_printn(CH_CFG_USE_MEMCORE);
 +test_println("");
 +test_print("*** CH_CFG_USE_HEAP:           ");
 +test_printn(CH_CFG_USE_HEAP);
 +test_println("");
 +test_print("*** CH_CFG_USE_MEMPOOLS:       ");
 +test_printn(CH_CFG_USE_MEMPOOLS);
 +test_println("");
 +test_print("*** CH_CFG_USE_DYNAMIC:        ");
 +test_printn(CH_CFG_USE_DYNAMIC);
 +test_println("");
 +test_print("*** CH_DBG_STATISTICS:         ");
 +test_printn(CH_DBG_STATISTICS);
 +test_println("");
 +test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
 +test_printn(CH_DBG_SYSTEM_STATE_CHECK);
 +test_println("");
 +test_print("*** CH_DBG_ENABLE_CHECKS:      ");
 +test_printn(CH_DBG_ENABLE_CHECKS);
 +test_println("");
 +test_print("*** CH_DBG_ENABLE_ASSERTS:     ");
 +test_printn(CH_DBG_ENABLE_ASSERTS);
 +test_println("");
 +test_print("*** CH_DBG_TRACE_MASK:         ");
 +test_printn(CH_DBG_TRACE_MASK);
 +test_println("");
 +test_print("*** CH_DBG_TRACE_BUFFER_SIZE:  ");
 +test_printn(CH_DBG_TRACE_BUFFER_SIZE);
 +test_println("");
 +test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
 +test_printn(CH_DBG_ENABLE_STACK_CHECK);
 +test_println("");
 +test_print("*** CH_DBG_FILL_THREADS:       ");
 +test_printn(CH_DBG_FILL_THREADS);
 +test_println("");
 +test_print("*** CH_DBG_THREADS_PROFILING:  ");
 +test_printn(CH_DBG_THREADS_PROFILING);
 +test_println("");]]></value>
 +                    </code>
 +                  </step>
 +                </steps>
 +              </case>
 +            </cases>
 +          </sequence>
 +          <sequence>
 +            <type index="0">
 +              <value>Internal Tests</value>
 +            </type>
 +            <brief>
                <value>System layer and port interface.</value>
              </brief>
              <description>
 diff --git a/test/rt/source/test/test_root.c b/test/rt/source/test/test_root.c index 5754813ac..876c738fe 100644 --- a/test/rt/source/test/test_root.c +++ b/test/rt/source/test/test_root.c @@ -33,6 +33,7 @@   * - @subpage test_sequence_010
   * - @subpage test_sequence_011
   * - @subpage test_sequence_012
 + * - @subpage test_sequence_013
   * .
   */
 @@ -58,31 +59,32 @@ const testcase_t * const *test_suite[] = {    test_sequence_001,
    test_sequence_002,
    test_sequence_003,
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    test_sequence_004,
 -#endif
 -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    test_sequence_005,
  #endif
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
    test_sequence_006,
  #endif
 -#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
    test_sequence_007,
  #endif
 -#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
    test_sequence_008,
  #endif
 -#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
    test_sequence_009,
  #endif
 -#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
    test_sequence_010,
  #endif
 -#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
    test_sequence_011,
  #endif
 +#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
    test_sequence_012,
 +#endif
 +  test_sequence_013,
    NULL
  };
 diff --git a/test/rt/source/test/test_root.h b/test/rt/source/test/test_root.h index 4fdc5ec57..2a0853df8 100644 --- a/test/rt/source/test/test_root.h +++ b/test/rt/source/test/test_root.h @@ -34,6 +34,7 @@  #include "test_sequence_010.h"
  #include "test_sequence_011.h"
  #include "test_sequence_012.h"
 +#include "test_sequence_013.h"
  #if !defined(__DOXYGEN__)
 diff --git a/test/rt/source/test/test_sequence_001.c b/test/rt/source/test/test_sequence_001.c index 9003fa153..6cde4ca1e 100644 --- a/test/rt/source/test/test_sequence_001.c +++ b/test/rt/source/test/test_sequence_001.c @@ -22,22 +22,17 @@   * @file    test_sequence_001.c
   * @brief   Test Sequence 001 code.
   *
 - * @page test_sequence_001 [1] System layer and port interface
 + * @page test_sequence_001 [1] Information
   *
   * File: @ref test_sequence_001.c
   *
   * <h2>Description</h2>
 - * The functionality of the system layer and port interface is tested.
 - * Basic RT functionality is taken for granted or this test suite could
 - * not even be executed. Errors in implementation are detected by
 - * executing this sequence with the state checker enabled
 - * (CH_DBG_STATE_CHECKER=TRUE).
 + * This sequence reports configuration and version information about
 + * the RT kernel.
   *
   * <h2>Test Cases</h2>
   * - @subpage test_001_001
   * - @subpage test_001_002
 - * - @subpage test_001_003
 - * - @subpage test_001_004
   * .
   */
 @@ -45,238 +40,190 @@   * Shared code.
   ****************************************************************************/
 -/* Timer callback for testing system functions in ISR context.*/
 -static void vtcb(void *p) {
 -  syssts_t sts;
 -
 -  (void)p;
 -
 -  /* Testing normal case.*/
 -  chSysLockFromISR();
 -  chSysUnlockFromISR();
 -
 -  /* Reentrant case.*/
 -  chSysLockFromISR();
 -  sts = chSysGetStatusAndLockX();
 -  chSysRestoreStatusX(sts);
 -  chSysUnlockFromISR();
 -}
 +#include "ch.h"
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_001_001 [1.1] System integrity functionality
 + * @page test_001_001 [1.1] Kernel Info
   *
   * <h2>Description</h2>
 - * The system self-test functionality is invoked in order to make an
 - * initial system state assessment and for coverage.
 + * The version numbers are reported.
   *
   * <h2>Test Steps</h2>
 - * - [1.1.1] Testing Ready List integrity.
 - * - [1.1.2] Testing Virtual Timers List integrity.
 - * - [1.1.3] Testing Registry List integrity.
 - * - [1.1.4] Testing Port-defined integrity.
 + * - [1.1.1] Prints the version string.
   * .
   */
  static void test_001_001_execute(void) {
 -  bool result;
 -  /* [1.1.1] Testing Ready List integrity.*/
 +  /* [1.1.1] Prints the version string.*/
    test_set_step(1);
    {
 -    chSysLock();
 -    result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
 -    chSysUnlock();
 -    test_assert(result == false, "ready list check failed");
 -  }
 -
 -  /* [1.1.2] Testing Virtual Timers List integrity.*/
 -  test_set_step(2);
 -  {
 -    chSysLock();
 -    result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
 -    chSysUnlock();
 -    test_assert(result == false, "virtual timers list check failed");
 -  }
 -
 -  /* [1.1.3] Testing Registry List integrity.*/
 -  test_set_step(3);
 -  {
 -    chSysLock();
 -    result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
 -    chSysUnlock();
 -    test_assert(result == false, "registry list check failed");
 -  }
 -
 -  /* [1.1.4] Testing Port-defined integrity.*/
 -  test_set_step(4);
 -  {
 -    chSysLock();
 -    result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
 -    chSysUnlock();
 -    test_assert(result == false, "port layer check failed");
 +    test_println("*** Product:                   ChibiOS/RT");
 +    test_print("*** Stable Flag:               ");
 +    test_printn(CH_KERNEL_STABLE);
 +    test_println("");
 +    test_print("*** Version String:            ");
 +    test_println(CH_KERNEL_VERSION);
 +    test_print("*** Major Number:              ");
 +    test_printn(CH_KERNEL_MAJOR);
 +    test_println("");
 +    test_print("*** Minor Number:              ");
 +    test_printn(CH_KERNEL_MINOR);
 +    test_println("");
 +    test_print("*** Patch Number:              ");
 +    test_printn(CH_KERNEL_PATCH);
 +    test_println("");
    }
  }
  static const testcase_t test_001_001 = {
 -  "System integrity functionality",
 +  "Kernel Info",
    NULL,
    NULL,
    test_001_001_execute
  };
  /**
 - * @page test_001_002 [1.2] Critical zones functionality
 + * @page test_001_002 [1.2] Kernel Settings
   *
   * <h2>Description</h2>
 - * The critical zones API is invoked for coverage.
 + * The static kernel settings are reported.
   *
   * <h2>Test Steps</h2>
 - * - [1.2.1] Testing chSysGetStatusAndLockX() and
 - *   chSysRestoreStatusX(), non reentrant case.
 - * - [1.2.2] Testing chSysGetStatusAndLockX() and
 - *   chSysRestoreStatusX(), reentrant case.
 - * - [1.2.3] Testing chSysUnconditionalLock().
 - * - [1.2.4] Testing chSysUnconditionalUnlock().
 - * - [1.2.5] Testing from ISR context using a virtual timer.
 + * - [1.2.1] Prints the configuration options settings.
   * .
   */
  static void test_001_002_execute(void) {
 -  syssts_t sts;
 -  virtual_timer_t vt;
 -  /* [1.2.1] Testing chSysGetStatusAndLockX() and
 -     chSysRestoreStatusX(), non reentrant case.*/
 +  /* [1.2.1] Prints the configuration options settings.*/
    test_set_step(1);
    {
 -    sts = chSysGetStatusAndLockX();
 -    chSysRestoreStatusX(sts);
 -  }
 -
 -  /* [1.2.2] Testing chSysGetStatusAndLockX() and
 -     chSysRestoreStatusX(), reentrant case.*/
 -  test_set_step(2);
 -  {
 -    chSysLock();
 -    sts = chSysGetStatusAndLockX();
 -    chSysRestoreStatusX(sts);
 -    chSysUnlock();
 -  }
 -
 -  /* [1.2.3] Testing chSysUnconditionalLock().*/
 -  test_set_step(3);
 -  {
 -    chSysUnconditionalLock();
 -    chSysUnconditionalLock();
 -    chSysUnlock();
 -  }
 -
 -  /* [1.2.4] Testing chSysUnconditionalUnlock().*/
 -  test_set_step(4);
 -  {
 -    chSysLock();
 -    chSysUnconditionalUnlock();
 -    chSysUnconditionalUnlock();
 -  }
 -
 -  /* [1.2.5] Testing from ISR context using a virtual timer.*/
 -  test_set_step(5);
 -  {
 -    chVTObjectInit(&vt);
 -    chVTSet(&vt, 1, vtcb, NULL);
 -    chThdSleep(10);
 -
 -    test_assert(chVTIsArmed(&vt) == false, "timer still armed");
 +    test_print("*** CH_CFG_ST_RESOLUTION:      ");
 +    test_printn(CH_CFG_ST_RESOLUTION);
 +    test_println("");
 +    test_print("*** CH_CFG_ST_FREQUENCY:       ");
 +    test_printn(CH_CFG_ST_FREQUENCY);
 +    test_println("");
 +    test_print("*** CH_CFG_ST_TIMEDELTA:       ");
 +    test_printn(CH_CFG_ST_TIMEDELTA);
 +    test_println("");
 +    test_print("*** CH_CFG_TIME_QUANTUM:       ");
 +    test_printn(CH_CFG_TIME_QUANTUM);
 +    test_println("");
 +    test_print("*** CH_CFG_MEMCORE_SIZE:       ");
 +    test_printn(CH_CFG_MEMCORE_SIZE);
 +    test_println("");
 +    test_print("*** CH_CFG_NO_IDLE_THREAD:     ");
 +    test_printn(CH_CFG_NO_IDLE_THREAD);
 +    test_println("");
 +    test_print("*** CH_CFG_OPTIMIZE_SPEED:     ");
 +    test_printn(CH_CFG_OPTIMIZE_SPEED);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_TM:             ");
 +    test_printn(CH_CFG_USE_TM);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_REGISTRY:       ");
 +    test_printn(CH_CFG_USE_REGISTRY);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_WAITEXIT:       ");
 +    test_printn(CH_CFG_USE_WAITEXIT);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_SEMAPHORES:     ");
 +    test_printn(CH_CFG_USE_SEMAPHORES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_SEMAPHORES_PRI: ");
 +    test_printn(CH_CFG_USE_SEMAPHORES_PRIORITY);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MUTEXES:        ");
 +    test_printn(CH_CFG_USE_MUTEXES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MUTEXES_RECURS: ");
 +    test_printn(CH_CFG_USE_MUTEXES_RECURSIVE);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_CONDVARS:       ");
 +    test_printn(CH_CFG_USE_CONDVARS);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_CONDVARS_TIMEO: ");
 +    test_printn(CH_CFG_USE_CONDVARS_TIMEOUT);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_EVENTS:         ");
 +    test_printn(CH_CFG_USE_EVENTS);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_EVENTS_TIMEOUT: ");
 +    test_printn(CH_CFG_USE_EVENTS_TIMEOUT);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MESSAGES:       ");
 +    test_printn(CH_CFG_USE_MESSAGES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MESSAGES_PRI:   ");
 +    test_printn(CH_CFG_USE_MESSAGES_PRIORITY);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MAILBOXES:      ");
 +    test_printn(CH_CFG_USE_MAILBOXES);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MEMCORE:        ");
 +    test_printn(CH_CFG_USE_MEMCORE);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_HEAP:           ");
 +    test_printn(CH_CFG_USE_HEAP);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_MEMPOOLS:       ");
 +    test_printn(CH_CFG_USE_MEMPOOLS);
 +    test_println("");
 +    test_print("*** CH_CFG_USE_DYNAMIC:        ");
 +    test_printn(CH_CFG_USE_DYNAMIC);
 +    test_println("");
 +    test_print("*** CH_DBG_STATISTICS:         ");
 +    test_printn(CH_DBG_STATISTICS);
 +    test_println("");
 +    test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
 +    test_printn(CH_DBG_SYSTEM_STATE_CHECK);
 +    test_println("");
 +    test_print("*** CH_DBG_ENABLE_CHECKS:      ");
 +    test_printn(CH_DBG_ENABLE_CHECKS);
 +    test_println("");
 +    test_print("*** CH_DBG_ENABLE_ASSERTS:     ");
 +    test_printn(CH_DBG_ENABLE_ASSERTS);
 +    test_println("");
 +    test_print("*** CH_DBG_TRACE_MASK:         ");
 +    test_printn(CH_DBG_TRACE_MASK);
 +    test_println("");
 +    test_print("*** CH_DBG_TRACE_BUFFER_SIZE:  ");
 +    test_printn(CH_DBG_TRACE_BUFFER_SIZE);
 +    test_println("");
 +    test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
 +    test_printn(CH_DBG_ENABLE_STACK_CHECK);
 +    test_println("");
 +    test_print("*** CH_DBG_FILL_THREADS:       ");
 +    test_printn(CH_DBG_FILL_THREADS);
 +    test_println("");
 +    test_print("*** CH_DBG_THREADS_PROFILING:  ");
 +    test_printn(CH_DBG_THREADS_PROFILING);
 +    test_println("");
    }
  }
  static const testcase_t test_001_002 = {
 -  "Critical zones functionality",
 +  "Kernel Settings",
    NULL,
    NULL,
    test_001_002_execute
  };
 -/**
 - * @page test_001_003 [1.3] Interrupts handling functionality
 - *
 - * <h2>Description</h2>
 - * The interrupts handling API is invoked for coverage.
 - *
 - * <h2>Test Steps</h2>
 - * - [1.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable().
 - * .
 - */
 -
 -static void test_001_003_execute(void) {
 -
 -  /* [1.3.1] Testing chSysSuspend(), chSysDisable() and
 -     chSysEnable().*/
 -  test_set_step(1);
 -  {
 -    chSysSuspend();
 -    chSysDisable();
 -    chSysSuspend();
 -    chSysEnable();
 -  }
 -}
 -
 -static const testcase_t test_001_003 = {
 -  "Interrupts handling functionality",
 -  NULL,
 -  NULL,
 -  test_001_003_execute
 -};
 -
 -/**
 - * @page test_001_004 [1.4] System Tick Counter functionality
 - *
 - * <h2>Description</h2>
 - * The functionality of the API @p chVTGetSystemTimeX() is tested.
 - *
 - * <h2>Test Steps</h2>
 - * - [1.4.1] A System Tick Counter increment is expected, the test
 - *   simply hangs if it does not happen.
 - * .
 - */
 -
 -static void test_001_004_execute(void) {
 -
 -  /* [1.4.1] A System Tick Counter increment is expected, the test
 -     simply hangs if it does not happen.*/
 -  test_set_step(1);
 -  {
 -    systime_t time = chVTGetSystemTimeX();
 -    while (time == chVTGetSystemTimeX()) {
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    }
 -  }
 -}
 -
 -static const testcase_t test_001_004 = {
 -  "System Tick Counter functionality",
 -  NULL,
 -  NULL,
 -  test_001_004_execute
 -};
 -
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   System layer and port interface.
 + * @brief   Information.
   */
  const testcase_t * const test_sequence_001[] = {
    &test_001_001,
    &test_001_002,
 -  &test_001_003,
 -  &test_001_004,
    NULL
  };
 diff --git a/test/rt/source/test/test_sequence_002.c b/test/rt/source/test/test_sequence_002.c index a712021c6..52a3ff7d7 100644 --- a/test/rt/source/test/test_sequence_002.c +++ b/test/rt/source/test/test_sequence_002.c @@ -22,13 +22,16 @@   * @file    test_sequence_002.c
   * @brief   Test Sequence 002 code.
   *
 - * @page test_sequence_002 [2] Threads Functionality
 + * @page test_sequence_002 [2] System layer and port interface
   *
   * File: @ref test_sequence_002.c
   *
   * <h2>Description</h2>
 - * This sequence tests the ChibiOS/RT functionalities related to
 - * threading.
 + * The functionality of the system layer and port interface is tested.
 + * Basic RT functionality is taken for granted or this test suite could
 + * not even be executed. Errors in implementation are detected by
 + * executing this sequence with the state checker enabled
 + * (CH_DBG_STATE_CHECKER=TRUE).
   *
   * <h2>Test Cases</h2>
   * - @subpage test_002_001
 @@ -42,9 +45,21 @@   * Shared code.
   ****************************************************************************/
 -static THD_FUNCTION(thread, p) {
 +/* Timer callback for testing system functions in ISR context.*/
 +static void vtcb(void *p) {
 +  syssts_t sts;
 -  test_emit_token(*(char *)p);
 +  (void)p;
 +
 +  /* Testing normal case.*/
 +  chSysLockFromISR();
 +  chSysUnlockFromISR();
 +
 +  /* Reentrant case.*/
 +  chSysLockFromISR();
 +  sts = chSysGetStatusAndLockX();
 +  chSysRestoreStatusX(sts);
 +  chSysUnlockFromISR();
  }
  /****************************************************************************
 @@ -52,293 +67,216 @@ static THD_FUNCTION(thread, p) {   ****************************************************************************/
  /**
 - * @page test_002_001 [2.1] Thread Sleep functionality
 + * @page test_002_001 [2.1] System integrity functionality
   *
   * <h2>Description</h2>
 - * The functionality of @p chThdSleep() and derivatives is tested.
 + * The system self-test functionality is invoked in order to make an
 + * initial system state assessment and for coverage.
   *
   * <h2>Test Steps</h2>
 - * - [2.1.1] The current system time is read then a sleep is performed
 - *   for 100 system ticks and on exit the system time is verified
 - *   again.
 - * - [2.1.2] The current system time is read then a sleep is performed
 - *   for 100000 microseconds and on exit the system time is verified
 - *   again.
 - * - [2.1.3] The current system time is read then a sleep is performed
 - *   for 100 milliseconds and on exit the system time is verified
 - *   again.
 - * - [2.1.4] The current system time is read then a sleep is performed
 - *   for 1 second and on exit the system time is verified again.
 - * - [2.1.5] Function chThdSleepUntil() is tested with a timeline of
 - *   "now" + 100 ticks.
 + * - [2.1.1] Testing Ready List integrity.
 + * - [2.1.2] Testing Virtual Timers List integrity.
 + * - [2.1.3] Testing Registry List integrity.
 + * - [2.1.4] Testing Port-defined integrity.
   * .
   */
  static void test_002_001_execute(void) {
 -  systime_t time;
 +  bool result;
 -  /* [2.1.1] The current system time is read then a sleep is performed
 -     for 100 system ticks and on exit the system time is verified
 -     again.*/
 +  /* [2.1.1] Testing Ready List integrity.*/
    test_set_step(1);
    {
 -    time = chVTGetSystemTimeX();
 -    chThdSleep(100);
 -    test_assert_time_window(time + 100,
 -                            time + 100 + CH_CFG_ST_TIMEDELTA + 1,
 -                            "out of time window");
 +    chSysLock();
 +    result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
 +    chSysUnlock();
 +    test_assert(result == false, "ready list check failed");
    }
 -  /* [2.1.2] The current system time is read then a sleep is performed
 -     for 100000 microseconds and on exit the system time is verified
 -     again.*/
 +  /* [2.1.2] Testing Virtual Timers List integrity.*/
    test_set_step(2);
    {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepMicroseconds(100000);
 -    test_assert_time_window(time + US2ST(100000),
 -                            time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1,
 -                            "out of time window");
 +    chSysLock();
 +    result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
 +    chSysUnlock();
 +    test_assert(result == false, "virtual timers list check failed");
    }
 -  /* [2.1.3] The current system time is read then a sleep is performed
 -     for 100 milliseconds and on exit the system time is verified
 -     again.*/
 +  /* [2.1.3] Testing Registry List integrity.*/
    test_set_step(3);
    {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepMilliseconds(100);
 -    test_assert_time_window(time + MS2ST(100),
 -                            time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1,
 -                            "out of time window");
 +    chSysLock();
 +    result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
 +    chSysUnlock();
 +    test_assert(result == false, "registry list check failed");
    }
 -  /* [2.1.4] The current system time is read then a sleep is performed
 -     for 1 second and on exit the system time is verified again.*/
 +  /* [2.1.4] Testing Port-defined integrity.*/
    test_set_step(4);
    {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepSeconds(1);
 -    test_assert_time_window(time + S2ST(1),
 -                            time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1,
 -                            "out of time window");
 -  }
 -
 -  /* [2.1.5] Function chThdSleepUntil() is tested with a timeline of
 -     "now" + 100 ticks.*/
 -  test_set_step(5);
 -  {
 -    time = chVTGetSystemTimeX();
 -    chThdSleepUntil(time + 100);
 -    test_assert_time_window(time + 100,
 -                            time + 100 + CH_CFG_ST_TIMEDELTA + 1,
 -                            "out of time window");
 +    chSysLock();
 +    result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
 +    chSysUnlock();
 +    test_assert(result == false, "port layer check failed");
    }
  }
  static const testcase_t test_002_001 = {
 -  "Thread Sleep functionality",
 +  "System integrity functionality",
    NULL,
    NULL,
    test_002_001_execute
  };
  /**
 - * @page test_002_002 [2.2] Ready List functionality, threads priority order
 + * @page test_002_002 [2.2] Critical zones functionality
   *
   * <h2>Description</h2>
 - * Five threads, are enqueued in the ready list and atomically
 - * executed. The test expects the threads to perform their operations
 - * in correct priority order regardless of the initial order.
 + * The critical zones API is invoked for coverage.
   *
   * <h2>Test Steps</h2>
 - * - [2.2.1] Creating 5 threads with increasing priority, execution
 - *   sequence is tested.
 - * - [2.2.2] Creating 5 threads with decreasing priority, execution
 - *   sequence is tested.
 - * - [2.2.3] Creating 5 threads with pseudo-random priority, execution
 - *   sequence is tested.
 + * - [2.2.1] Testing chSysGetStatusAndLockX() and
 + *   chSysRestoreStatusX(), non reentrant case.
 + * - [2.2.2] Testing chSysGetStatusAndLockX() and
 + *   chSysRestoreStatusX(), reentrant case.
 + * - [2.2.3] Testing chSysUnconditionalLock().
 + * - [2.2.4] Testing chSysUnconditionalUnlock().
 + * - [2.2.5] Testing from ISR context using a virtual timer.
   * .
   */
  static void test_002_002_execute(void) {
 +  syssts_t sts;
 +  virtual_timer_t vt;
 -  /* [2.2.1] Creating 5 threads with increasing priority, execution
 -     sequence is tested.*/
 +  /* [2.2.1] Testing chSysGetStatusAndLockX() and
 +     chSysRestoreStatusX(), non reentrant case.*/
    test_set_step(1);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
 -    test_wait_threads();
 -    test_assert_sequence("ABCDE", "invalid sequence");
 +    sts = chSysGetStatusAndLockX();
 +    chSysRestoreStatusX(sts);
    }
 -  /* [2.2.2] Creating 5 threads with decreasing priority, execution
 -     sequence is tested.*/
 +  /* [2.2.2] Testing chSysGetStatusAndLockX() and
 +     chSysRestoreStatusX(), reentrant case.*/
    test_set_step(2);
    {
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
 -    test_wait_threads();
 -    test_assert_sequence("ABCDE", "invalid sequence");
 +    chSysLock();
 +    sts = chSysGetStatusAndLockX();
 +    chSysRestoreStatusX(sts);
 +    chSysUnlock();
    }
 -  /* [2.2.3] Creating 5 threads with pseudo-random priority, execution
 -     sequence is tested.*/
 +  /* [2.2.3] Testing chSysUnconditionalLock().*/
    test_set_step(3);
    {
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
 -    test_wait_threads();
 -    test_assert_sequence("ABCDE", "invalid sequence");
 +    chSysUnconditionalLock();
 +    chSysUnconditionalLock();
 +    chSysUnlock();
 +  }
 +
 +  /* [2.2.4] Testing chSysUnconditionalUnlock().*/
 +  test_set_step(4);
 +  {
 +    chSysLock();
 +    chSysUnconditionalUnlock();
 +    chSysUnconditionalUnlock();
 +  }
 +
 +  /* [2.2.5] Testing from ISR context using a virtual timer.*/
 +  test_set_step(5);
 +  {
 +    chVTObjectInit(&vt);
 +    chVTSet(&vt, 1, vtcb, NULL);
 +    chThdSleep(10);
 +
 +    test_assert(chVTIsArmed(&vt) == false, "timer still armed");
    }
  }
  static const testcase_t test_002_002 = {
 -  "Ready List functionality, threads priority order",
 +  "Critical zones functionality",
    NULL,
    NULL,
    test_002_002_execute
  };
  /**
 - * @page test_002_003 [2.3] Priority change test
 + * @page test_002_003 [2.3] Interrupts handling functionality
   *
   * <h2>Description</h2>
 - * A series of priority changes are performed on the current thread in
 - * order to verify that the priority change happens as expected.
 + * The interrupts handling API is invoked for coverage.
   *
   * <h2>Test Steps</h2>
 - * - [2.3.1] Thread priority is increased by one then a check is
 - *   performed.
 - * - [2.3.2] Thread priority is returned to the previous value then a
 - *   check is performed.
 + * - [2.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable().
   * .
   */
  static void test_002_003_execute(void) {
 -  tprio_t prio, p1;
 -  /* [2.3.1] Thread priority is increased by one then a check is
 -     performed.*/
 +  /* [2.3.1] Testing chSysSuspend(), chSysDisable() and
 +     chSysEnable().*/
    test_set_step(1);
    {
 -    prio = chThdGetPriorityX();
 -    p1 = chThdSetPriority(prio + 1);
 -    test_assert(p1 == prio, "unexpected returned priority level");
 -    test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
 -  }
 -
 -  /* [2.3.2] Thread priority is returned to the previous value then a
 -     check is performed.*/
 -  test_set_step(2);
 -  {
 -    p1 = chThdSetPriority(p1);
 -    test_assert(p1 == prio + 1, "unexpected returned priority level");
 -    test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
 +    chSysSuspend();
 +    chSysDisable();
 +    chSysSuspend();
 +    chSysEnable();
    }
  }
  static const testcase_t test_002_003 = {
 -  "Priority change test",
 +  "Interrupts handling functionality",
    NULL,
    NULL,
    test_002_003_execute
  };
 -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
  /**
 - * @page test_002_004 [2.4] Priority change test with Priority Inheritance
 + * @page test_002_004 [2.4] System Tick Counter functionality
   *
   * <h2>Description</h2>
 - * A series of priority changes are performed on the current thread in
 - * order to verify that the priority change happens as expected.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_MUTEXES
 - * .
 + * The functionality of the API @p chVTGetSystemTimeX() is tested.
   *
   * <h2>Test Steps</h2>
 - * - [2.4.1] Simulating a priority boost situation (prio > realprio).
 - * - [2.4.2] Raising thread priority above original priority but below
 - *   the boosted level.
 - * - [2.4.3] Raising thread priority above the boosted level.
 - * - [2.4.4] Restoring original conditions.
 + * - [2.4.1] A System Tick Counter increment is expected, the test
 + *   simply hangs if it does not happen.
   * .
   */
  static void test_002_004_execute(void) {
 -  tprio_t prio, p1;
 -  /* [2.4.1] Simulating a priority boost situation (prio > realprio).*/
 +  /* [2.4.1] A System Tick Counter increment is expected, the test
 +     simply hangs if it does not happen.*/
    test_set_step(1);
    {
 -    prio = chThdGetPriorityX();
 -    chThdGetSelfX()->prio += 2;
 -    test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
 -  }
 -
 -  /* [2.4.2] Raising thread priority above original priority but below
 -     the boosted level.*/
 -  test_set_step(2);
 -  {
 -    p1 = chThdSetPriority(prio + 1);
 -    test_assert(p1 == prio, "unexpected returned priority level");
 -    test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
 -    test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
 -  }
 -
 -  /* [2.4.3] Raising thread priority above the boosted level.*/
 -  test_set_step(3);
 -  {
 -    p1 = chThdSetPriority(prio + 3);
 -    test_assert(p1 == prio + 1, "unexpected returned priority level");
 -    test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
 -    test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
 -  }
 -
 -  /* [2.4.4] Restoring original conditions.*/
 -  test_set_step(4);
 -  {
 -    chSysLock();
 -    chThdGetSelfX()->prio = prio;
 -    chThdGetSelfX()->realprio = prio;
 -    chSysUnlock();
 +    systime_t time = chVTGetSystemTimeX();
 +    while (time == chVTGetSystemTimeX()) {
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    }
    }
  }
  static const testcase_t test_002_004 = {
 -  "Priority change test with Priority Inheritance",
 +  "System Tick Counter functionality",
    NULL,
    NULL,
    test_002_004_execute
  };
 -#endif /* CH_CFG_USE_MUTEXES */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Threads Functionality.
 + * @brief   System layer and port interface.
   */
  const testcase_t * const test_sequence_002[] = {
    &test_002_001,
    &test_002_002,
    &test_002_003,
 -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
    &test_002_004,
 -#endif
    NULL
  };
 diff --git a/test/rt/source/test/test_sequence_003.c b/test/rt/source/test/test_sequence_003.c index 3f29a30c7..4232708c7 100644 --- a/test/rt/source/test/test_sequence_003.c +++ b/test/rt/source/test/test_sequence_003.c @@ -22,16 +22,19 @@   * @file    test_sequence_003.c
   * @brief   Test Sequence 003 code.
   *
 - * @page test_sequence_003 [3] Suspend/Resume
 + * @page test_sequence_003 [3] Threads Functionality
   *
   * File: @ref test_sequence_003.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/RT functionalities related to
 - * threads suspend/resume.
 + * threading.
   *
   * <h2>Test Cases</h2>
   * - @subpage test_003_001
 + * - @subpage test_003_002
 + * - @subpage test_003_003
 + * - @subpage test_003_004
   * .
   */
 @@ -39,14 +42,8 @@   * Shared code.
   ****************************************************************************/
 -static thread_reference_t tr1;
 +static THD_FUNCTION(thread, p) {
 -static THD_FUNCTION(thread1, p) {
 -
 -  chSysLock();
 -  chThdResumeI(&tr1, MSG_OK);
 -  chSchRescheduleS();
 -  chSysUnlock();
    test_emit_token(*(char *)p);
  }
 @@ -55,76 +52,293 @@ static THD_FUNCTION(thread1, p) {   ****************************************************************************/
  /**
 - * @page test_003_001 [3.1] Suspend and Resume functionality
 + * @page test_003_001 [3.1] Thread Sleep functionality
   *
   * <h2>Description</h2>
 - * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
 - * tested.
 + * The functionality of @p chThdSleep() and derivatives is tested.
   *
   * <h2>Test Steps</h2>
 - * - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 - *   is remotely resumed with message @p MSG_OK. On return the message
 - *   and the state of the reference are tested.
 - * - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 - *   is not resumed so a timeout must occur. On return the message and
 - *   the state of the reference are tested.
 + * - [3.1.1] The current system time is read then a sleep is performed
 + *   for 100 system ticks and on exit the system time is verified
 + *   again.
 + * - [3.1.2] The current system time is read then a sleep is performed
 + *   for 100000 microseconds and on exit the system time is verified
 + *   again.
 + * - [3.1.3] The current system time is read then a sleep is performed
 + *   for 100 milliseconds and on exit the system time is verified
 + *   again.
 + * - [3.1.4] The current system time is read then a sleep is performed
 + *   for 1 second and on exit the system time is verified again.
 + * - [3.1.5] Function chThdSleepUntil() is tested with a timeline of
 + *   "now" + 100 ticks.
   * .
   */
 -static void test_003_001_setup(void) {
 -  tr1 = NULL;
 -}
 -
  static void test_003_001_execute(void) {
    systime_t time;
 -  msg_t msg;
 -  /* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 -     is remotely resumed with message @p MSG_OK. On return the message
 -     and the state of the reference are tested.*/
 +  /* [3.1.1] The current system time is read then a sleep is performed
 +     for 100 system ticks and on exit the system time is verified
 +     again.*/
    test_set_step(1);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
 -    chSysLock();
 -    msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
 -    chSysUnlock();
 -    test_assert(NULL == tr1, "not NULL");
 -    test_assert(MSG_OK == msg,"wrong returned message");
 -    test_wait_threads();
 +    time = chVTGetSystemTimeX();
 +    chThdSleep(100);
 +    test_assert_time_window(time + 100,
 +                            time + 100 + CH_CFG_ST_TIMEDELTA + 1,
 +                            "out of time window");
    }
 -  /* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 -     is not resumed so a timeout must occur. On return the message and
 -     the state of the reference are tested.*/
 +  /* [3.1.2] The current system time is read then a sleep is performed
 +     for 100000 microseconds and on exit the system time is verified
 +     again.*/
    test_set_step(2);
    {
 -    chSysLock();
      time = chVTGetSystemTimeX();
 -    msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
 -    chSysUnlock();
 -    test_assert_time_window(time + MS2ST(1000),
 -                            time + MS2ST(1000) + CH_CFG_ST_TIMEDELTA + 1,
 +    chThdSleepMicroseconds(100000);
 +    test_assert_time_window(time + US2ST(100000),
 +                            time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1,
 +                            "out of time window");
 +  }
 +
 +  /* [3.1.3] The current system time is read then a sleep is performed
 +     for 100 milliseconds and on exit the system time is verified
 +     again.*/
 +  test_set_step(3);
 +  {
 +    time = chVTGetSystemTimeX();
 +    chThdSleepMilliseconds(100);
 +    test_assert_time_window(time + MS2ST(100),
 +                            time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1,
 +                            "out of time window");
 +  }
 +
 +  /* [3.1.4] The current system time is read then a sleep is performed
 +     for 1 second and on exit the system time is verified again.*/
 +  test_set_step(4);
 +  {
 +    time = chVTGetSystemTimeX();
 +    chThdSleepSeconds(1);
 +    test_assert_time_window(time + S2ST(1),
 +                            time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1,
 +                            "out of time window");
 +  }
 +
 +  /* [3.1.5] Function chThdSleepUntil() is tested with a timeline of
 +     "now" + 100 ticks.*/
 +  test_set_step(5);
 +  {
 +    time = chVTGetSystemTimeX();
 +    chThdSleepUntil(time + 100);
 +    test_assert_time_window(time + 100,
 +                            time + 100 + CH_CFG_ST_TIMEDELTA + 1,
                              "out of time window");
 -    test_assert(NULL == tr1, "not NULL");
 -    test_assert(MSG_TIMEOUT == msg, "wrong returned message");
    }
  }
  static const testcase_t test_003_001 = {
 -  "Suspend and Resume functionality",
 -  test_003_001_setup,
 +  "Thread Sleep functionality",
 +  NULL,
    NULL,
    test_003_001_execute
  };
 +/**
 + * @page test_003_002 [3.2] Ready List functionality, threads priority order
 + *
 + * <h2>Description</h2>
 + * Five threads, are enqueued in the ready list and atomically
 + * executed. The test expects the threads to perform their operations
 + * in correct priority order regardless of the initial order.
 + *
 + * <h2>Test Steps</h2>
 + * - [3.2.1] Creating 5 threads with increasing priority, execution
 + *   sequence is tested.
 + * - [3.2.2] Creating 5 threads with decreasing priority, execution
 + *   sequence is tested.
 + * - [3.2.3] Creating 5 threads with pseudo-random priority, execution
 + *   sequence is tested.
 + * .
 + */
 +
 +static void test_003_002_execute(void) {
 +
 +  /* [3.2.1] Creating 5 threads with increasing priority, execution
 +     sequence is tested.*/
 +  test_set_step(1);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
 +    test_wait_threads();
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +  }
 +
 +  /* [3.2.2] Creating 5 threads with decreasing priority, execution
 +     sequence is tested.*/
 +  test_set_step(2);
 +  {
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
 +    test_wait_threads();
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +  }
 +
 +  /* [3.2.3] Creating 5 threads with pseudo-random priority, execution
 +     sequence is tested.*/
 +  test_set_step(3);
 +  {
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
 +    test_wait_threads();
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +  }
 +}
 +
 +static const testcase_t test_003_002 = {
 +  "Ready List functionality, threads priority order",
 +  NULL,
 +  NULL,
 +  test_003_002_execute
 +};
 +
 +/**
 + * @page test_003_003 [3.3] Priority change test
 + *
 + * <h2>Description</h2>
 + * A series of priority changes are performed on the current thread in
 + * order to verify that the priority change happens as expected.
 + *
 + * <h2>Test Steps</h2>
 + * - [3.3.1] Thread priority is increased by one then a check is
 + *   performed.
 + * - [3.3.2] Thread priority is returned to the previous value then a
 + *   check is performed.
 + * .
 + */
 +
 +static void test_003_003_execute(void) {
 +  tprio_t prio, p1;
 +
 +  /* [3.3.1] Thread priority is increased by one then a check is
 +     performed.*/
 +  test_set_step(1);
 +  {
 +    prio = chThdGetPriorityX();
 +    p1 = chThdSetPriority(prio + 1);
 +    test_assert(p1 == prio, "unexpected returned priority level");
 +    test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
 +  }
 +
 +  /* [3.3.2] Thread priority is returned to the previous value then a
 +     check is performed.*/
 +  test_set_step(2);
 +  {
 +    p1 = chThdSetPriority(p1);
 +    test_assert(p1 == prio + 1, "unexpected returned priority level");
 +    test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
 +  }
 +}
 +
 +static const testcase_t test_003_003 = {
 +  "Priority change test",
 +  NULL,
 +  NULL,
 +  test_003_003_execute
 +};
 +
 +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +/**
 + * @page test_003_004 [3.4] Priority change test with Priority Inheritance
 + *
 + * <h2>Description</h2>
 + * A series of priority changes are performed on the current thread in
 + * order to verify that the priority change happens as expected.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_MUTEXES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [3.4.1] Simulating a priority boost situation (prio > realprio).
 + * - [3.4.2] Raising thread priority above original priority but below
 + *   the boosted level.
 + * - [3.4.3] Raising thread priority above the boosted level.
 + * - [3.4.4] Restoring original conditions.
 + * .
 + */
 +
 +static void test_003_004_execute(void) {
 +  tprio_t prio, p1;
 +
 +  /* [3.4.1] Simulating a priority boost situation (prio > realprio).*/
 +  test_set_step(1);
 +  {
 +    prio = chThdGetPriorityX();
 +    chThdGetSelfX()->prio += 2;
 +    test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
 +  }
 +
 +  /* [3.4.2] Raising thread priority above original priority but below
 +     the boosted level.*/
 +  test_set_step(2);
 +  {
 +    p1 = chThdSetPriority(prio + 1);
 +    test_assert(p1 == prio, "unexpected returned priority level");
 +    test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
 +    test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
 +  }
 +
 +  /* [3.4.3] Raising thread priority above the boosted level.*/
 +  test_set_step(3);
 +  {
 +    p1 = chThdSetPriority(prio + 3);
 +    test_assert(p1 == prio + 1, "unexpected returned priority level");
 +    test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
 +    test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
 +  }
 +
 +  /* [3.4.4] Restoring original conditions.*/
 +  test_set_step(4);
 +  {
 +    chSysLock();
 +    chThdGetSelfX()->prio = prio;
 +    chThdGetSelfX()->realprio = prio;
 +    chSysUnlock();
 +  }
 +}
 +
 +static const testcase_t test_003_004 = {
 +  "Priority change test with Priority Inheritance",
 +  NULL,
 +  NULL,
 +  test_003_004_execute
 +};
 +#endif /* CH_CFG_USE_MUTEXES */
 +
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Suspend/Resume.
 + * @brief   Threads Functionality.
   */
  const testcase_t * const test_sequence_003[] = {
    &test_003_001,
 +  &test_003_002,
 +  &test_003_003,
 +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +  &test_003_004,
 +#endif
    NULL
  };
 diff --git a/test/rt/source/test/test_sequence_004.c b/test/rt/source/test/test_sequence_004.c index eb62cfb76..d20b36506 100644 --- a/test/rt/source/test/test_sequence_004.c +++ b/test/rt/source/test/test_sequence_004.c @@ -22,66 +22,32 @@   * @file    test_sequence_004.c
   * @brief   Test Sequence 004 code.
   *
 - * @page test_sequence_004 [4] Counter and Binary Semaphores
 + * @page test_sequence_004 [4] Suspend/Resume
   *
   * File: @ref test_sequence_004.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/RT functionalities related to
 - * counter semaphores.
 - *
 - * <h2>Conditions</h2>
 - * This sequence is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 + * threads suspend/resume.
   *
   * <h2>Test Cases</h2>
   * - @subpage test_004_001
 - * - @subpage test_004_002
 - * - @subpage test_004_003
 - * - @subpage test_004_004
 - * - @subpage test_004_005
 - * - @subpage test_004_006
   * .
   */
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 -
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#include "ch.h"
 -
 -static semaphore_t sem1;
 +static thread_reference_t tr1;
  static THD_FUNCTION(thread1, p) {
 -  chSemWait(&sem1);
 -  test_emit_token(*(char *)p);
 -}
 -
 -static THD_FUNCTION(thread2, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(50);
    chSysLock();
 -  chSemSignalI(&sem1); /* For coverage reasons */
 +  chThdResumeI(&tr1, MSG_OK);
    chSchRescheduleS();
    chSysUnlock();
 -}
 -
 -static THD_FUNCTION(thread3, p) {
 -
 -  (void)p;
 -  chSemWait(&sem1);
 -  chSemSignal(&sem1);
 -}
 -
 -static THD_FUNCTION(thread4, p) {
 -
 -  chBSemSignal((binary_semaphore_t *)p);
 +  test_emit_token(*(char *)p);
  }
  /****************************************************************************
 @@ -89,403 +55,66 @@ static THD_FUNCTION(thread4, p) {   ****************************************************************************/
  /**
 - * @page test_004_001 [4.1] Semaphore primitives, no state change
 + * @page test_004_001 [4.1] Suspend and Resume functionality
   *
   * <h2>Description</h2>
 - * Wait, Signal and Reset primitives are tested. The testing thread
 - * does not trigger a state change.
 + * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
 + * tested.
   *
   * <h2>Test Steps</h2>
 - * - [4.1.1] The function chSemWait() is invoked, after return the
 - *   counter and the returned message are tested.
 - * - [4.1.2] The function chSemSignal() is invoked, after return the
 - *   counter is tested.
 - * - [4.1.3] The function chSemReset() is invoked, after return the
 - *   counter is tested.
 + * - [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 + *   is remotely resumed with message @p MSG_OK. On return the message
 + *   and the state of the reference are tested.
 + * - [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 + *   is not resumed so a timeout must occur. On return the message and
 + *   the state of the reference are tested.
   * .
   */
  static void test_004_001_setup(void) {
 -  chSemObjectInit(&sem1, 1);
 -}
 -
 -static void test_004_001_teardown(void) {
 -  chSemReset(&sem1, 0);
 +  tr1 = NULL;
  }
  static void test_004_001_execute(void) {
 -
 -  /* [4.1.1] The function chSemWait() is invoked, after return the
 -     counter and the returned message are tested.*/
 -  test_set_step(1);
 -  {
 -    msg_t msg;
 -
 -    msg = chSemWait(&sem1);
 -    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 -    test_assert(MSG_OK == msg, "wrong returned message");
 -  }
 -
 -  /* [4.1.2] The function chSemSignal() is invoked, after return the
 -     counter is tested.*/
 -  test_set_step(2);
 -  {
 -    chSemSignal(&sem1);
 -    test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
 -  }
 -
 -  /* [4.1.3] The function chSemReset() is invoked, after return the
 -     counter is tested.*/
 -  test_set_step(3);
 -  {
 -    chSemReset(&sem1, 2);
 -    test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
 -  }
 -}
 -
 -static const testcase_t test_004_001 = {
 -  "Semaphore primitives, no state change",
 -  test_004_001_setup,
 -  test_004_001_teardown,
 -  test_004_001_execute
 -};
 -
 -/**
 - * @page test_004_002 [4.2] Semaphore enqueuing test
 - *
 - * <h2>Description</h2>
 - * Five threads with randomized priorities are enqueued to a semaphore
 - * then awakened one at time. The test expects that the threads reach
 - * their goal in FIFO order or priority order depending on the @p
 - * CH_CFG_USE_SEMAPHORES_PRIORITY configuration setting.
 - *
 - * <h2>Test Steps</h2>
 - * - [4.2.1] Five threads are created with mixed priority levels (not
 - *   increasing nor decreasing). Threads enqueue on a semaphore
 - *   initialized to zero.
 - * - [4.2.2] The semaphore is signaled 5 times. The thread activation
 - *   sequence is tested.
 - * .
 - */
 -
 -static void test_004_002_setup(void) {
 -  chSemObjectInit(&sem1, 0);
 -}
 -
 -static void test_004_002_execute(void) {
 -
 -  /* [4.2.1] Five threads are created with mixed priority levels (not
 -     increasing nor decreasing). Threads enqueue on a semaphore
 -     initialized to zero.*/
 -  test_set_step(1);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D");
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E");
 -  }
 -
 -  /* [4.2.2] The semaphore is signaled 5 times. The thread activation
 -     sequence is tested.*/
 -  test_set_step(2);
 -  {
 -    chSemSignal(&sem1);
 -    chSemSignal(&sem1);
 -    chSemSignal(&sem1);
 -    chSemSignal(&sem1);
 -    chSemSignal(&sem1);
 -    test_wait_threads();
 -#if CH_CFG_USE_SEMAPHORES_PRIORITY
 -    test_assert_sequence("ADCEB", "invalid sequence");
 -#else
 -    test_assert_sequence("ABCDE", "invalid sequence");
 -#endif
 -  }
 -}
 -
 -static const testcase_t test_004_002 = {
 -  "Semaphore enqueuing test",
 -  test_004_002_setup,
 -  NULL,
 -  test_004_002_execute
 -};
 -
 -/**
 - * @page test_004_003 [4.3] Semaphore timeout test
 - *
 - * <h2>Description</h2>
 - * The three possible semaphore waiting modes (do not wait, wait with
 - * timeout, wait without timeout) are explored. The test expects that
 - * the semaphore wait function returns the correct value in each of the
 - * above scenario and that the semaphore structure status is correct
 - * after each operation.
 - *
 - * <h2>Test Steps</h2>
 - * - [4.3.1] Testing special case TIME_IMMEDIATE.
 - * - [4.3.2] Testing non-timeout condition.
 - * - [4.3.3] Testing timeout condition.
 - * .
 - */
 -
 -static void test_004_003_setup(void) {
 -  chSemObjectInit(&sem1, 0);
 -}
 -
 -static void test_004_003_execute(void) {
 -  unsigned i;
 -  systime_t target_time;
 +  systime_t time;
    msg_t msg;
 -  /* [4.3.1] Testing special case TIME_IMMEDIATE.*/
 -  test_set_step(1);
 -  {
 -    msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
 -    test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
 -    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 -    test_assert(sem1.cnt == 0, "counter not zero");
 -  }
 -
 -  /* [4.3.2] Testing non-timeout condition.*/
 -  test_set_step(2);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 -                                   thread2, 0);
 -    msg = chSemWaitTimeout(&sem1, MS2ST(500));
 -    test_wait_threads();
 -    test_assert(msg == MSG_OK, "wrong wake-up message");
 -    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 -    test_assert(sem1.cnt == 0, "counter not zero");
 -  }
 -
 -  /* [4.3.3] Testing timeout condition.*/
 -  test_set_step(3);
 -  {
 -    target_time = test_wait_tick() + MS2ST(5 * 50);
 -    for (i = 0; i < 5; i++) {
 -      test_emit_token('A' + i);
 -      msg = chSemWaitTimeout(&sem1, MS2ST(50));
 -      test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
 -      test_assert(queue_isempty(&sem1.queue), "queue not empty");
 -      test_assert(sem1.cnt == 0, "counter not zero");
 -    }
 -    test_assert_sequence("ABCDE", "invalid sequence");
 -    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 -                            "out of time window");
 -  }
 -}
 -
 -static const testcase_t test_004_003 = {
 -  "Semaphore timeout test",
 -  test_004_003_setup,
 -  NULL,
 -  test_004_003_execute
 -};
 -
 -/**
 - * @page test_004_004 [4.4] Testing chSemAddCounterI() functionality
 - *
 - * <h2>Description</h2>
 - * The functon is tested by waking up a thread then the semaphore
 - * counter value is tested.
 - *
 - * <h2>Test Steps</h2>
 - * - [4.4.1] A thread is created, it goes to wait on the semaphore.
 - * - [4.4.2] The semaphore counter is increased by two, it is then
 - *   tested to be one, the thread must have completed.
 - * .
 - */
 -
 -static void test_004_004_setup(void) {
 -  chSemObjectInit(&sem1, 0);
 -}
 -
 -static void test_004_004_execute(void) {
 -
 -  /* [4.4.1] A thread is created, it goes to wait on the semaphore.*/
 +  /* [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
 +     is remotely resumed with message @p MSG_OK. On return the message
 +     and the state of the reference are tested.*/
    test_set_step(1);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A");
 -  }
 -
 -  /* [4.4.2] The semaphore counter is increased by two, it is then
 -     tested to be one, the thread must have completed.*/
 -  test_set_step(2);
 -  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
      chSysLock();
 -    chSemAddCounterI(&sem1, 2);
 -    chSchRescheduleS();
 +    msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
      chSysUnlock();
 +    test_assert(NULL == tr1, "not NULL");
 +    test_assert(MSG_OK == msg,"wrong returned message");
      test_wait_threads();
 -    test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
 -    test_assert_sequence("A", "invalid sequence");
 -  }
 -}
 -
 -static const testcase_t test_004_004 = {
 -  "Testing chSemAddCounterI() functionality",
 -  test_004_004_setup,
 -  NULL,
 -  test_004_004_execute
 -};
 -
 -/**
 - * @page test_004_005 [4.5] Testing chSemWaitSignal() functionality
 - *
 - * <h2>Description</h2>
 - * This test case explicitly addresses the @p chSemWaitSignal()
 - * function. A thread is created that performs a wait and a signal
 - * operations. The tester thread is awakened from an atomic wait/signal
 - * operation. The test expects that the semaphore wait function returns
 - * the correct value in each of the above scenario and that the
 - * semaphore structure status is correct after each operation.
 - *
 - * <h2>Test Steps</h2>
 - * - [4.5.1] An higher priority thread is created that performs
 - *   non-atomical wait and signal operations on a semaphore.
 - * - [4.5.2] The function chSemSignalWait() is invoked by specifying
 - *   the same semaphore for the wait and signal phases. The counter
 - *   value must be one on exit.
 - * - [4.5.3] The function chSemSignalWait() is invoked again by
 - *   specifying the same semaphore for the wait and signal phases. The
 - *   counter value must be one on exit.
 - * .
 - */
 -
 -static void test_004_005_setup(void) {
 -  chSemObjectInit(&sem1, 0);
 -}
 -
 -static void test_004_005_teardown(void) {
 -  test_wait_threads();
 -}
 -
 -static void test_004_005_execute(void) {
 -
 -  /* [4.5.1] An higher priority thread is created that performs
 -     non-atomical wait and signal operations on a semaphore.*/
 -  test_set_step(1);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0);
 -  }
 -
 -  /* [4.5.2] The function chSemSignalWait() is invoked by specifying
 -     the same semaphore for the wait and signal phases. The counter
 -     value must be one on exit.*/
 -  test_set_step(2);
 -  {
 -    chSemSignalWait(&sem1, &sem1);
 -    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 -    test_assert(sem1.cnt == 0, "counter not zero");
 -  }
 -
 -  /* [4.5.3] The function chSemSignalWait() is invoked again by
 -     specifying the same semaphore for the wait and signal phases. The
 -     counter value must be one on exit.*/
 -  test_set_step(3);
 -  {
 -    chSemSignalWait(&sem1, &sem1);
 -    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 -    test_assert(sem1.cnt == 0, "counter not zero");
 -  }
 -}
 -
 -static const testcase_t test_004_005 = {
 -  "Testing chSemWaitSignal() functionality",
 -  test_004_005_setup,
 -  test_004_005_teardown,
 -  test_004_005_execute
 -};
 -
 -/**
 - * @page test_004_006 [4.6] Testing Binary Semaphores special case
 - *
 - * <h2>Description</h2>
 - * This test case tests the binary semaphores functionality. The test
 - * both checks the binary semaphore status and the expected status of
 - * the underlying counting semaphore.
 - *
 - * <h2>Test Steps</h2>
 - * - [4.6.1] Creating a binary semaphore in "taken" state, the state is
 - *   checked.
 - * - [4.6.2] Resetting the binary semaphore in "taken" state, the state
 - *   must not change.
 - * - [4.6.3] Starting a signaler thread at a lower priority.
 - * - [4.6.4] Waiting for the binary semaphore to be signaled, the
 - *   semaphore is expected to be taken.
 - * - [4.6.5] Signaling the binary semaphore, checking the binary
 - *   semaphore state to be "not taken" and the underlying counter
 - *   semaphore counter to be one.
 - * - [4.6.6] Signaling the binary semaphore again, the internal state
 - *   must not change from "not taken".
 - * .
 - */
 -
 -static void test_004_006_teardown(void) {
 -  test_wait_threads();
 -}
 -
 -static void test_004_006_execute(void) {
 -  binary_semaphore_t bsem;
 -  msg_t msg;
 -
 -  /* [4.6.1] Creating a binary semaphore in "taken" state, the state is
 -     checked.*/
 -  test_set_step(1);
 -  {
 -    chBSemObjectInit(&bsem, true);
 -    test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
    }
 -  /* [4.6.2] Resetting the binary semaphore in "taken" state, the state
 -     must not change.*/
 +  /* [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
 +     is not resumed so a timeout must occur. On return the message and
 +     the state of the reference are tested.*/
    test_set_step(2);
    {
 -    chBSemReset(&bsem, true);
 -    test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
 -  }
 -
 -  /* [4.6.3] Starting a signaler thread at a lower priority.*/
 -  test_set_step(3);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE,
 -                                   chThdGetPriorityX()-1, thread4, &bsem);
 -  }
 -
 -  /* [4.6.4] Waiting for the binary semaphore to be signaled, the
 -     semaphore is expected to be taken.*/
 -  test_set_step(4);
 -  {
 -    msg = chBSemWait(&bsem);
 -    test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
 -    test_assert(msg == MSG_OK, "unexpected message");
 -  }
 -
 -  /* [4.6.5] Signaling the binary semaphore, checking the binary
 -     semaphore state to be "not taken" and the underlying counter
 -     semaphore counter to be one.*/
 -  test_set_step(5);
 -  {
 -    chBSemSignal(&bsem);
 -    test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken");
 -    test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
 -  }
 -
 -  /* [4.6.6] Signaling the binary semaphore again, the internal state
 -     must not change from "not taken".*/
 -  test_set_step(6);
 -  {
 -    chBSemSignal(&bsem);
 -    test_assert_lock(chBSemGetStateI(&bsem) == false, "taken");
 -    test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
 +    chSysLock();
 +    time = chVTGetSystemTimeX();
 +    msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
 +    chSysUnlock();
 +    test_assert_time_window(time + MS2ST(1000),
 +                            time + MS2ST(1000) + CH_CFG_ST_TIMEDELTA + 1,
 +                            "out of time window");
 +    test_assert(NULL == tr1, "not NULL");
 +    test_assert(MSG_TIMEOUT == msg, "wrong returned message");
    }
  }
 -static const testcase_t test_004_006 = {
 -  "Testing Binary Semaphores special case",
 +static const testcase_t test_004_001 = {
 +  "Suspend and Resume functionality",
 +  test_004_001_setup,
    NULL,
 -  test_004_006_teardown,
 -  test_004_006_execute
 +  test_004_001_execute
  };
  /****************************************************************************
 @@ -493,16 +122,9 @@ static const testcase_t test_004_006 = {   ****************************************************************************/
  /**
 - * @brief   Counter and Binary Semaphores.
 + * @brief   Suspend/Resume.
   */
  const testcase_t * const test_sequence_004[] = {
    &test_004_001,
 -  &test_004_002,
 -  &test_004_003,
 -  &test_004_004,
 -  &test_004_005,
 -  &test_004_006,
    NULL
  };
 -
 -#endif /* CH_CFG_USE_SEMAPHORES */
 diff --git a/test/rt/source/test/test_sequence_005.c b/test/rt/source/test/test_sequence_005.c index 8b584d4de..4fe9bcc74 100644 --- a/test/rt/source/test/test_sequence_005.c +++ b/test/rt/source/test/test_sequence_005.c @@ -22,18 +22,18 @@   * @file    test_sequence_005.c
   * @brief   Test Sequence 005 code.
   *
 - * @page test_sequence_005 [5] Mutexes, Condition Variables and Priority Inheritance
 + * @page test_sequence_005 [5] Counter and Binary Semaphores
   *
   * File: @ref test_sequence_005.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/RT functionalities related to
 - * mutexes, condition variables and priority inheritance algorithm.
 + * counter semaphores.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MUTEXES
 + * - CH_CFG_USE_SEMAPHORES
   * .
   *
   * <h2>Test Cases</h2>
 @@ -43,1027 +43,466 @@   * - @subpage test_005_004
   * - @subpage test_005_005
   * - @subpage test_005_006
 - * - @subpage test_005_007
 - * - @subpage test_005_008
 - * - @subpage test_005_009
   * .
   */
 -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -static MUTEX_DECL(m1);
 -static MUTEX_DECL(m2);
 -#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
 -static CONDVAR_DECL(c1);
 -#endif
 +#include "ch.h"
 -#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
 -/**
 - * @brief   CPU pulse.
 - * @note    The current implementation is not totally reliable.
 - *
 - * @param[in] duration      CPU pulse duration in milliseconds
 - */
 -void test_cpu_pulse(unsigned duration) {
 -  systime_t start, end, now;
 -
 -  start = chThdGetTicksX(chThdGetSelfX());
 -  end = start + MS2ST(duration);
 -  do {
 -    now = chThdGetTicksX(chThdGetSelfX());
 -#if defined(SIMULATOR)
 -    _sim_check_for_interrupts();
 -#endif
 -  }
 -  while (chVTIsTimeWithinX(now, start, end));
 -}
 -#endif /* CH_DBG_THREADS_PROFILING */
 +static semaphore_t sem1;
  static THD_FUNCTION(thread1, p) {
 -  chMtxLock(&m1);
 +  chSemWait(&sem1);
    test_emit_token(*(char *)p);
 -  chMtxUnlock(&m1);
 -}
 -
 -#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
 -/* Low priority thread */
 -static THD_FUNCTION(thread2L, p) {
 -
 -  (void)p;
 -  chMtxLock(&m1);
 -  test_cpu_pulse(40);
 -  chMtxUnlock(&m1);
 -  test_cpu_pulse(10);
 -  test_emit_token('C');
 -}
 -
 -/* Medium priority thread */
 -static THD_FUNCTION(thread2M, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(20);
 -  test_cpu_pulse(40);
 -  test_emit_token('B');
 -}
 -
 -/* High priority thread */
 -static THD_FUNCTION(thread2H, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(40);
 -  chMtxLock(&m1);
 -  test_cpu_pulse(10);
 -  chMtxUnlock(&m1);
 -  test_emit_token('A');
 -}
 -
 -/* Lowest priority thread */
 -static THD_FUNCTION(thread3LL, p) {
 -
 -  (void)p;
 -  chMtxLock(&m1);
 -  test_cpu_pulse(30);
 -  chMtxUnlock(&m1);
 -  test_emit_token('E');
 -}
 -
 -/* Low priority thread */
 -static THD_FUNCTION(thread3L, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(10);
 -  chMtxLock(&m2);
 -  test_cpu_pulse(20);
 -  chMtxLock(&m1);
 -  test_cpu_pulse(10);
 -  chMtxUnlock(&m1);
 -  test_cpu_pulse(10);
 -  chMtxUnlock(&m2);
 -  test_emit_token('D');
 -}
 -
 -/* Medium priority thread */
 -static THD_FUNCTION(thread3M, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(20);
 -  chMtxLock(&m2);
 -  test_cpu_pulse(10);
 -  chMtxUnlock(&m2);
 -  test_emit_token('C');
 -}
 -
 -/* High priority thread */
 -static THD_FUNCTION(thread3H, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(40);
 -  test_cpu_pulse(20);
 -  test_emit_token('B');
  }
 -/* Highest priority thread */
 -static THD_FUNCTION(thread3HH, p) {
 +static THD_FUNCTION(thread2, p) {
    (void)p;
    chThdSleepMilliseconds(50);
 -  chMtxLock(&m2);
 -  test_cpu_pulse(10);
 -  chMtxUnlock(&m2);
 -  test_emit_token('A');
 -}
 -#endif /* CH_DBG_THREADS_PROFILING */
 -
 -static THD_FUNCTION(thread4A, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(50);
 -  chMtxLock(&m1);
 -  chMtxUnlock(&m1);
 -}
 -
 -static THD_FUNCTION(thread4B, p) {
 -
 -  (void)p;
 -  chThdSleepMilliseconds(150);
    chSysLock();
 -  chMtxLockS(&m2);   /* For coverage of the chMtxLockS() function variant.*/
 -  chMtxUnlockS(&m2); /* For coverage of the chMtxUnlockS() function variant.*/
 +  chSemSignalI(&sem1); /* For coverage reasons */
    chSchRescheduleS();
    chSysUnlock();
  }
 -#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
 -static THD_FUNCTION(thread6, p) {
 -
 -  chMtxLock(&m1);
 -  chCondWait(&c1);
 -  test_emit_token(*(char *)p);
 -  chMtxUnlock(&m1);
 -}
 -
 -static THD_FUNCTION(thread8, p) {
 +static THD_FUNCTION(thread3, p) {
 -  chMtxLock(&m2);
 -  chMtxLock(&m1);
 -#if CH_CFG_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__)
 -  chCondWaitTimeout(&c1, TIME_INFINITE);
 -#else
 -  chCondWait(&c1);
 -#endif
 -  test_emit_token(*(char *)p);
 -  chMtxUnlock(&m1);
 -  chMtxUnlock(&m2);
 +  (void)p;
 +  chSemWait(&sem1);
 +  chSemSignal(&sem1);
  }
 -static THD_FUNCTION(thread9, p) {
 +static THD_FUNCTION(thread4, p) {
 -  chMtxLock(&m2);
 -  test_emit_token(*(char *)p);
 -  chMtxUnlock(&m2);
 +  chBSemSignal((binary_semaphore_t *)p);
  }
 -#endif /* CH_CFG_USE_CONDVARS */
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_005_001 [5.1] Priority enqueuing test
 + * @page test_005_001 [5.1] Semaphore primitives, no state change
   *
   * <h2>Description</h2>
 - * Five threads, with increasing priority, are enqueued on a locked
 - * mutex then the mutex is unlocked. The test expects the threads to
 - * perform their operations in increasing priority order regardless of
 - * the initial order.
 + * Wait, Signal and Reset primitives are tested. The testing thread
 + * does not trigger a state change.
   *
   * <h2>Test Steps</h2>
 - * - [5.1.1] Getting the initial priority.
 - * - [5.1.2] Locking the mutex.
 - * - [5.1.3] Five threads are created that try to lock and unlock the
 - *   mutex then terminate. The threads are created in ascending
 - *   priority order.
 - * - [5.1.4] Unlocking the mutex, the threads will wakeup in priority
 - *   order because the mutext queue is an ordered one.
 + * - [5.1.1] The function chSemWait() is invoked, after return the
 + *   counter and the returned message are tested.
 + * - [5.1.2] The function chSemSignal() is invoked, after return the
 + *   counter is tested.
 + * - [5.1.3] The function chSemReset() is invoked, after return the
 + *   counter is tested.
   * .
   */
  static void test_005_001_setup(void) {
 -  chMtxObjectInit(&m1);
 +  chSemObjectInit(&sem1, 1);
 +}
 +
 +static void test_005_001_teardown(void) {
 +  chSemReset(&sem1, 0);
  }
  static void test_005_001_execute(void) {
 -  tprio_t prio;
 -  /* [5.1.1] Getting the initial priority.*/
 +  /* [5.1.1] The function chSemWait() is invoked, after return the
 +     counter and the returned message are tested.*/
    test_set_step(1);
    {
 -    prio = chThdGetPriorityX();
 +    msg_t msg;
 +
 +    msg = chSemWait(&sem1);
 +    test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
 +    test_assert(MSG_OK == msg, "wrong returned message");
    }
 -  /* [5.1.2] Locking the mutex.*/
 +  /* [5.1.2] The function chSemSignal() is invoked, after return the
 +     counter is tested.*/
    test_set_step(2);
    {
 -    chMtxLock(&m1);
 +    chSemSignal(&sem1);
 +    test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
    }
 -  /* [5.1.3] Five threads are created that try to lock and unlock the
 -     mutex then terminate. The threads are created in ascending
 -     priority order.*/
 +  /* [5.1.3] The function chSemReset() is invoked, after return the
 +     counter is tested.*/
    test_set_step(3);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread1, "E");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread1, "D");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread1, "C");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread1, "B");
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread1, "A");
 -  }
 -
 -  /* [5.1.4] Unlocking the mutex, the threads will wakeup in priority
 -     order because the mutext queue is an ordered one.*/
 -  test_set_step(4);
 -  {
 -    chMtxUnlock(&m1);
 -    test_wait_threads();
 -    test_assert(prio == chThdGetPriorityX(), "wrong priority level");
 -    test_assert_sequence("ABCDE", "invalid sequence");
 +    chSemReset(&sem1, 2);
 +    test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
    }
  }
  static const testcase_t test_005_001 = {
 -  "Priority enqueuing test",
 +  "Semaphore primitives, no state change",
    test_005_001_setup,
 -  NULL,
 +  test_005_001_teardown,
    test_005_001_execute
  };
 -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
  /**
 - * @page test_005_002 [5.2] Priority inheritance, simple case
 + * @page test_005_002 [5.2] Semaphore enqueuing test
   *
   * <h2>Description</h2>
 - * Three threads are involved in the classic priority inversion
 - * scenario, a medium priority thread tries to starve an high priority
 - * thread by blocking a low priority thread into a mutex lock zone. The
 - * test expects the threads to reach their goal in increasing priority
 - * order by rearranging their priorities in order to avoid the priority
 - * inversion trap.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_DBG_THREADS_PROFILING
 - * .
 + * Five threads with randomized priorities are enqueued to a semaphore
 + * then awakened one at time. The test expects that the threads reach
 + * their goal in FIFO order or priority order depending on the @p
 + * CH_CFG_USE_SEMAPHORES_PRIORITY configuration setting.
   *
   * <h2>Test Steps</h2>
 - * - [5.2.1] Getting the system time for test duration measurement.
 - * - [5.2.2] The three contenders threads are created and let run
 - *   atomically, the goals sequence is tested, the threads must
 - *   complete in priority order.
 - * - [5.2.3] Testing that all threads completed within the specified
 - *   time windows (100mS...100mS+ALLOWED_DELAY).
 + * - [5.2.1] Five threads are created with mixed priority levels (not
 + *   increasing nor decreasing). Threads enqueue on a semaphore
 + *   initialized to zero.
 + * - [5.2.2] The semaphore is signaled 5 times. The thread activation
 + *   sequence is tested.
   * .
   */
  static void test_005_002_setup(void) {
 -  chMtxObjectInit(&m1);
 +  chSemObjectInit(&sem1, 0);
  }
  static void test_005_002_execute(void) {
 -  systime_t time;
 -  /* [5.2.1] Getting the system time for test duration measurement.*/
 +  /* [5.2.1] Five threads are created with mixed priority levels (not
 +     increasing nor decreasing). Threads enqueue on a semaphore
 +     initialized to zero.*/
    test_set_step(1);
    {
 -    time = test_wait_tick();
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D");
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E");
    }
 -  /* [5.2.2] The three contenders threads are created and let run
 -     atomically, the goals sequence is tested, the threads must
 -     complete in priority order.*/
 +  /* [5.2.2] The semaphore is signaled 5 times. The thread activation
 +     sequence is tested.*/
    test_set_step(2);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread2H, 0);
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, thread2M, 0);
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread2L, 0);
 +    chSemSignal(&sem1);
 +    chSemSignal(&sem1);
 +    chSemSignal(&sem1);
 +    chSemSignal(&sem1);
 +    chSemSignal(&sem1);
      test_wait_threads();
 -    test_assert_sequence("ABC", "invalid sequence");
 -  }
 -
 -  /* [5.2.3] Testing that all threads completed within the specified
 -     time windows (100mS...100mS+ALLOWED_DELAY).*/
 -  test_set_step(3);
 -  {
 -    test_assert_time_window(time + MS2ST(100), time + MS2ST(100) + ALLOWED_DELAY,
 -                            "out of time window");
 +#if CH_CFG_USE_SEMAPHORES_PRIORITY
 +    test_assert_sequence("ADCEB", "invalid sequence");
 +#else
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +#endif
    }
  }
  static const testcase_t test_005_002 = {
 -  "Priority inheritance, simple case",
 +  "Semaphore enqueuing test",
    test_005_002_setup,
    NULL,
    test_005_002_execute
  };
 -#endif /* CH_DBG_THREADS_PROFILING */
 -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
  /**
 - * @page test_005_003 [5.3] Priority inheritance, complex case
 + * @page test_005_003 [5.3] Semaphore timeout test
   *
   * <h2>Description</h2>
 - * Five threads are involved in the complex priority inversion
 - * scenario, the priority inheritance algorithm is tested for depths
 - * greater than one. The test expects the threads to perform their
 - * operations in increasing priority order by rearranging their
 - * priorities in order to avoid the priority inversion trap.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_DBG_THREADS_PROFILING
 - * .
 + * The three possible semaphore waiting modes (do not wait, wait with
 + * timeout, wait without timeout) are explored. The test expects that
 + * the semaphore wait function returns the correct value in each of the
 + * above scenario and that the semaphore structure status is correct
 + * after each operation.
   *
   * <h2>Test Steps</h2>
 - * - [5.3.1] Getting the system time for test duration measurement.
 - * - [5.3.2] The five contenders threads are created and let run
 - *   atomically, the goals sequence is tested, the threads must
 - *   complete in priority order.
 - * - [5.3.3] Testing that all threads completed within the specified
 - *   time windows (110mS...110mS+ALLOWED_DELAY).
 + * - [5.3.1] Testing special case TIME_IMMEDIATE.
 + * - [5.3.2] Testing non-timeout condition.
 + * - [5.3.3] Testing timeout condition.
   * .
   */
  static void test_005_003_setup(void) {
 -  chMtxObjectInit(&m1); /* Mutex B.*/
 -  chMtxObjectInit(&m2); /* Mutex A.*/
 +  chSemObjectInit(&sem1, 0);
  }
  static void test_005_003_execute(void) {
 -  systime_t time;
 +  unsigned i;
 +  systime_t target_time;
 +  msg_t msg;
 -  /* [5.3.1] Getting the system time for test duration measurement.*/
 +  /* [5.3.1] Testing special case TIME_IMMEDIATE.*/
    test_set_step(1);
    {
 -    time = test_wait_tick();
 +    msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
 +    test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
 +    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 +    test_assert(sem1.cnt == 0, "counter not zero");
    }
 -  /* [5.3.2] The five contenders threads are created and let run
 -     atomically, the goals sequence is tested, the threads must
 -     complete in priority order.*/
 +  /* [5.3.2] Testing non-timeout condition.*/
    test_set_step(2);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread3LL, 0);
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread3L, 0);
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread3M, 0);
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread3H, 0);
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread3HH, 0);
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 +                                   thread2, 0);
 +    msg = chSemWaitTimeout(&sem1, MS2ST(500));
      test_wait_threads();
 -    test_assert_sequence("ABCDE", "invalid sequence");
 +    test_assert(msg == MSG_OK, "wrong wake-up message");
 +    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 +    test_assert(sem1.cnt == 0, "counter not zero");
    }
 -  /* [5.3.3] Testing that all threads completed within the specified
 -     time windows (110mS...110mS+ALLOWED_DELAY).*/
 +  /* [5.3.3] Testing timeout condition.*/
    test_set_step(3);
    {
 -    test_assert_time_window(time + MS2ST(110), time + MS2ST(110) + ALLOWED_DELAY,
 +    target_time = test_wait_tick() + MS2ST(5 * 50);
 +    for (i = 0; i < 5; i++) {
 +      test_emit_token('A' + i);
 +      msg = chSemWaitTimeout(&sem1, MS2ST(50));
 +      test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
 +      test_assert(queue_isempty(&sem1.queue), "queue not empty");
 +      test_assert(sem1.cnt == 0, "counter not zero");
 +    }
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
                              "out of time window");
    }
  }
  static const testcase_t test_005_003 = {
 -  "Priority inheritance, complex case",
 +  "Semaphore timeout test",
    test_005_003_setup,
    NULL,
    test_005_003_execute
  };
 -#endif /* CH_DBG_THREADS_PROFILING */
  /**
 - * @page test_005_004 [5.4] Priority return verification
 + * @page test_005_004 [5.4] Testing chSemAddCounterI() functionality
   *
   * <h2>Description</h2>
 - * Two threads are spawned that try to lock the mutexes already locked
 - * by the tester thread with precise timing. The test expects that the
 - * priority changes caused by the priority inheritance algorithm happen
 - * at the right moment and with the right values.<br> Thread A performs
 - * wait(50), lock(m1), unlock(m1), exit. Thread B performs wait(150),
 - * lock(m2), unlock(m2), exit.
 + * The functon is tested by waking up a thread then the semaphore
 + * counter value is tested.
   *
   * <h2>Test Steps</h2>
 - * - [5.4.1] Getting current thread priority P(0) and assigning to the
 - *   threads A and B priorities +1 and +2.
 - * - [5.4.2] Spawning threads A and B at priorities P(A) and P(B).
 - * - [5.4.3] Locking the mutex M1 before thread A has a chance to lock
 - *   it. The priority must not change because A has not yet reached
 - *   chMtxLock(M1). the mutex is not locked.
 - * - [5.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and
 - *   get the mutex. This must boost the priority of the current thread
 - *   at the same level of thread A.
 - * - [5.4.5] Locking the mutex M2 before thread B has a chance to lock
 - *   it. The priority must not change because B has not yet reached
 - *   chMtxLock(M2). the mutex is not locked.
 - * - [5.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and
 - *   get the mutex. This must boost the priority of the current thread
 - *   at the same level of thread B.
 - * - [5.4.7] Unlocking M2, the priority should fall back to P(A).
 - * - [5.4.8] Unlocking M1, the priority should fall back to P(0).
 + * - [5.4.1] A thread is created, it goes to wait on the semaphore.
 + * - [5.4.2] The semaphore counter is increased by two, it is then
 + *   tested to be one, the thread must have completed.
   * .
   */
  static void test_005_004_setup(void) {
 -  chMtxObjectInit(&m1);
 -  chMtxObjectInit(&m2);
 -}
 -
 -static void test_005_004_teardown(void) {
 -  test_wait_threads();
 +  chSemObjectInit(&sem1, 0);
  }
  static void test_005_004_execute(void) {
 -  tprio_t p, pa, pb;
 -  /* [5.4.1] Getting current thread priority P(0) and assigning to the
 -     threads A and B priorities +1 and +2.*/
 +  /* [5.4.1] A thread is created, it goes to wait on the semaphore.*/
    test_set_step(1);
    {
 -    p = chThdGetPriorityX();
 -    pa = p + 1;
 -    pb = p + 2;
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A");
    }
 -  /* [5.4.2] Spawning threads A and B at priorities P(A) and P(B).*/
 +  /* [5.4.2] The semaphore counter is increased by two, it is then
 +     tested to be one, the thread must have completed.*/
    test_set_step(2);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, pa, thread4A, "A");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, pb, thread4B, "B");
 -  }
 -
 -  /* [5.4.3] Locking the mutex M1 before thread A has a chance to lock
 -     it. The priority must not change because A has not yet reached
 -     chMtxLock(M1). the mutex is not locked.*/
 -  test_set_step(3);
 -  {
 -    chMtxLock(&m1);
 -    test_assert(chThdGetPriorityX() == p, "wrong priority level");
 -  }
 -
 -  /* [5.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and
 -     get the mutex. This must boost the priority of the current thread
 -     at the same level of thread A.*/
 -  test_set_step(4);
 -  {
 -    chThdSleepMilliseconds(100);
 -    test_assert(chThdGetPriorityX() == pa, "wrong priority level");
 -  }
 -
 -  /* [5.4.5] Locking the mutex M2 before thread B has a chance to lock
 -     it. The priority must not change because B has not yet reached
 -     chMtxLock(M2). the mutex is not locked.*/
 -  test_set_step(5);
 -  {
 -    chMtxLock(&m2);
 -    test_assert(chThdGetPriorityX() == pa, "wrong priority level");
 -  }
 -
 -  /* [5.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and
 -     get the mutex. This must boost the priority of the current thread
 -     at the same level of thread B.*/
 -  test_set_step(6);
 -  {
 -    chThdSleepMilliseconds(100);
 -    test_assert(chThdGetPriorityX() == pb, "wrong priority level");
 -  }
 -
 -  /* [5.4.7] Unlocking M2, the priority should fall back to P(A).*/
 -  test_set_step(7);
 -  {
 -    chMtxUnlock(&m2);
 -    test_assert(chThdGetPriorityX() == pa, "wrong priority level");
 -  }
 -
 -  /* [5.4.8] Unlocking M1, the priority should fall back to P(0).*/
 -  test_set_step(8);
 -  {
 -    chMtxUnlock(&m1);
 -    test_assert(chThdGetPriorityX() == p, "wrong priority level");
 +    chSysLock();
 +    chSemAddCounterI(&sem1, 2);
 +    chSchRescheduleS();
 +    chSysUnlock();
 +    test_wait_threads();
 +    test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
 +    test_assert_sequence("A", "invalid sequence");
    }
  }
  static const testcase_t test_005_004 = {
 -  "Priority return verification",
 +  "Testing chSemAddCounterI() functionality",
    test_005_004_setup,
 -  test_005_004_teardown,
 +  NULL,
    test_005_004_execute
  };
 -#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
  /**
 - * @page test_005_005 [5.5] Repeated locks, non recursive scenario
 + * @page test_005_005 [5.5] Testing chSemWaitSignal() functionality
   *
   * <h2>Description</h2>
 - * The behavior of multiple mutex locks from the same thread is tested
 - * when recursion is disabled.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - !CH_CFG_USE_MUTEXES_RECURSIVE
 - * .
 + * This test case explicitly addresses the @p chSemWaitSignal()
 + * function. A thread is created that performs a wait and a signal
 + * operations. The tester thread is awakened from an atomic wait/signal
 + * operation. The test expects that the semaphore wait function returns
 + * the correct value in each of the above scenario and that the
 + * semaphore structure status is correct after each operation.
   *
   * <h2>Test Steps</h2>
 - * - [5.5.1] Getting current thread priority for later checks.
 - * - [5.5.2] Locking the mutex first time, it must be possible because
 - *   it is not owned.
 - * - [5.5.3] Locking the mutex second time, it must fail because it is
 - *   already owned.
 - * - [5.5.4] Unlocking the mutex then it must not be owned anymore and
 - *   the queue must be empty.
 - * - [5.5.5] Testing that priority has not changed after operations.
 - * - [5.5.6] Testing chMtxUnlockAll() behavior.
 - * - [5.5.7] Testing that priority has not changed after operations.
 + * - [5.5.1] An higher priority thread is created that performs
 + *   non-atomical wait and signal operations on a semaphore.
 + * - [5.5.2] The function chSemSignalWait() is invoked by specifying
 + *   the same semaphore for the wait and signal phases. The counter
 + *   value must be one on exit.
 + * - [5.5.3] The function chSemSignalWait() is invoked again by
 + *   specifying the same semaphore for the wait and signal phases. The
 + *   counter value must be one on exit.
   * .
   */
  static void test_005_005_setup(void) {
 -  chMtxObjectInit(&m1);
 +  chSemObjectInit(&sem1, 0);
 +}
 +
 +static void test_005_005_teardown(void) {
 +  test_wait_threads();
  }
  static void test_005_005_execute(void) {
 -  bool b;
 -  tprio_t prio;
 -  /* [5.5.1] Getting current thread priority for later checks.*/
 +  /* [5.5.1] An higher priority thread is created that performs
 +     non-atomical wait and signal operations on a semaphore.*/
    test_set_step(1);
    {
 -    prio = chThdGetPriorityX();
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0);
    }
 -  /* [5.5.2] Locking the mutex first time, it must be possible because
 -     it is not owned.*/
 +  /* [5.5.2] The function chSemSignalWait() is invoked by specifying
 +     the same semaphore for the wait and signal phases. The counter
 +     value must be one on exit.*/
    test_set_step(2);
    {
 -    b = chMtxTryLock(&m1);
 -    test_assert(b, "already locked");
 +    chSemSignalWait(&sem1, &sem1);
 +    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 +    test_assert(sem1.cnt == 0, "counter not zero");
    }
 -  /* [5.5.3] Locking the mutex second time, it must fail because it is
 -     already owned.*/
 +  /* [5.5.3] The function chSemSignalWait() is invoked again by
 +     specifying the same semaphore for the wait and signal phases. The
 +     counter value must be one on exit.*/
    test_set_step(3);
    {
 -    b = chMtxTryLock(&m1);
 -    test_assert(!b, "not locked");
 -  }
 -
 -  /* [5.5.4] Unlocking the mutex then it must not be owned anymore and
 -     the queue must be empty.*/
 -  test_set_step(4);
 -  {
 -    chMtxUnlock(&m1);
 -    test_assert(m1.owner == NULL, "still owned");
 -    test_assert(queue_isempty(&m1.queue), "queue not empty");
 -  }
 -
 -  /* [5.5.5] Testing that priority has not changed after operations.*/
 -  test_set_step(5);
 -  {
 -    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 -  }
 -
 -  /* [5.5.6] Testing chMtxUnlockAll() behavior.*/
 -  test_set_step(6);
 -  {
 -    b = chMtxTryLock(&m1);
 -    test_assert(b, "already locked");
 -    b = chMtxTryLock(&m1);
 -    test_assert(!b, "not locked");
 -
 -    chMtxUnlockAll();
 -    test_assert(m1.owner == NULL, "still owned");
 -    test_assert(queue_isempty(&m1.queue), "queue not empty");
 -  }
 -
 -  /* [5.5.7] Testing that priority has not changed after operations.*/
 -  test_set_step(7);
 -  {
 -    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 +    chSemSignalWait(&sem1, &sem1);
 +    test_assert(queue_isempty(&sem1.queue), "queue not empty");
 +    test_assert(sem1.cnt == 0, "counter not zero");
    }
  }
  static const testcase_t test_005_005 = {
 -  "Repeated locks, non recursive scenario",
 +  "Testing chSemWaitSignal() functionality",
    test_005_005_setup,
 -  NULL,
 +  test_005_005_teardown,
    test_005_005_execute
  };
 -#endif /* !CH_CFG_USE_MUTEXES_RECURSIVE */
 -#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
  /**
 - * @page test_005_006 [5.6] Repeated locks using, recursive scenario
 + * @page test_005_006 [5.6] Testing Binary Semaphores special case
   *
   * <h2>Description</h2>
 - * The behavior of multiple mutex locks from the same thread is tested
 - * when recursion is enabled.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_MUTEXES_RECURSIVE
 - * .
 + * This test case tests the binary semaphores functionality. The test
 + * both checks the binary semaphore status and the expected status of
 + * the underlying counting semaphore.
   *
   * <h2>Test Steps</h2>
 - * - [5.6.1] Getting current thread priority for later checks.
 - * - [5.6.2] Locking the mutex first time, it must be possible because
 - *   it is not owned.
 - * - [5.6.3] Locking the mutex second time, it must be possible because
 - *   it is recursive.
 - * - [5.6.4] Unlocking the mutex then it must be still owned because
 - *   recursivity.
 - * - [5.6.5] Unlocking the mutex then it must not be owned anymore and
 - *   the queue must be empty.
 - * - [5.6.6] Testing that priority has not changed after operations.
 - * - [5.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls
 - *   and a final chMtxUnlockAllS().
 - * - [5.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a
 - *   final chMtxUnlockAll().
 - * - [5.6.9] Testing that priority has not changed after operations.
 + * - [5.6.1] Creating a binary semaphore in "taken" state, the state is
 + *   checked.
 + * - [5.6.2] Resetting the binary semaphore in "taken" state, the state
 + *   must not change.
 + * - [5.6.3] Starting a signaler thread at a lower priority.
 + * - [5.6.4] Waiting for the binary semaphore to be signaled, the
 + *   semaphore is expected to be taken.
 + * - [5.6.5] Signaling the binary semaphore, checking the binary
 + *   semaphore state to be "not taken" and the underlying counter
 + *   semaphore counter to be one.
 + * - [5.6.6] Signaling the binary semaphore again, the internal state
 + *   must not change from "not taken".
   * .
   */
 -static void test_005_006_setup(void) {
 -  chMtxObjectInit(&m1);
 +static void test_005_006_teardown(void) {
 +  test_wait_threads();
  }
  static void test_005_006_execute(void) {
 -  bool b;
 -  tprio_t prio;
 +  binary_semaphore_t bsem;
 +  msg_t msg;
 -  /* [5.6.1] Getting current thread priority for later checks.*/
 +  /* [5.6.1] Creating a binary semaphore in "taken" state, the state is
 +     checked.*/
    test_set_step(1);
    {
 -    prio = chThdGetPriorityX();
 +    chBSemObjectInit(&bsem, true);
 +    test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
    }
 -  /* [5.6.2] Locking the mutex first time, it must be possible because
 -     it is not owned.*/
 +  /* [5.6.2] Resetting the binary semaphore in "taken" state, the state
 +     must not change.*/
    test_set_step(2);
    {
 -    b = chMtxTryLock(&m1);
 -    test_assert(b, "already locked");
 +    chBSemReset(&bsem, true);
 +    test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
    }
 -  /* [5.6.3] Locking the mutex second time, it must be possible because
 -     it is recursive.*/
 +  /* [5.6.3] Starting a signaler thread at a lower priority.*/
    test_set_step(3);
    {
 -    b = chMtxTryLock(&m1);
 -    test_assert(b, "already locked");
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE,
 +                                   chThdGetPriorityX()-1, thread4, &bsem);
    }
 -  /* [5.6.4] Unlocking the mutex then it must be still owned because
 -     recursivity.*/
 +  /* [5.6.4] Waiting for the binary semaphore to be signaled, the
 +     semaphore is expected to be taken.*/
    test_set_step(4);
    {
 -    chMtxUnlock(&m1);
 -    test_assert(m1.owner != NULL, "not owned");
 +    msg = chBSemWait(&bsem);
 +    test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
 +    test_assert(msg == MSG_OK, "unexpected message");
    }
 -  /* [5.6.5] Unlocking the mutex then it must not be owned anymore and
 -     the queue must be empty.*/
 +  /* [5.6.5] Signaling the binary semaphore, checking the binary
 +     semaphore state to be "not taken" and the underlying counter
 +     semaphore counter to be one.*/
    test_set_step(5);
    {
 -    chMtxUnlock(&m1);
 -    test_assert(m1.owner == NULL, "still owned");
 -    test_assert(queue_isempty(&m1.queue), "queue not empty");
 +    chBSemSignal(&bsem);
 +    test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken");
 +    test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
    }
 -  /* [5.6.6] Testing that priority has not changed after operations.*/
 +  /* [5.6.6] Signaling the binary semaphore again, the internal state
 +     must not change from "not taken".*/
    test_set_step(6);
    {
 -    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 -  }
 -
 -  /* [5.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls
 -     and a final chMtxUnlockAllS().*/
 -  test_set_step(7);
 -  {
 -    b = chMtxTryLock(&m1);
 -    test_assert(b, "already locked");
 -    chSysLock();
 -    b = chMtxTryLockS(&m1);
 -    chSysUnlock();
 -    test_assert(b, "already locked");
 -    test_assert(m1.cnt == 2, "invalid recursion counter");
 -    chSysLock();
 -    chMtxUnlockAllS();
 -    chSysUnlock();
 -    test_assert(m1.owner == NULL, "still owned");
 -    test_assert(queue_isempty(&m1.queue), "queue not empty");
 -    test_assert(m1.cnt == 0, "invalid recursion counter");
 -  }
 -
 -  /* [5.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a
 -     final chMtxUnlockAll().*/
 -  test_set_step(8);
 -  {
 -    chMtxLock(&m1);
 -    test_assert(m1.owner != NULL, "not owned");
 -    chSysLock();
 -    chMtxLockS(&m1);
 -    chSysUnlock();
 -    test_assert(m1.owner != NULL, "not owned");
 -    test_assert(m1.cnt == 2, "invalid recursion counter");
 -    chMtxUnlockAll();
 -    test_assert(m1.owner == NULL, "still owned");
 -    test_assert(queue_isempty(&m1.queue), "queue not empty");
 -    test_assert(m1.cnt == 0, "invalid recursion counter");
 -  }
 -
 -  /* [5.6.9] Testing that priority has not changed after operations.*/
 -  test_set_step(9);
 -  {
 -    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 +    chBSemSignal(&bsem);
 +    test_assert_lock(chBSemGetStateI(&bsem) == false, "taken");
 +    test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
    }
  }
  static const testcase_t test_005_006 = {
 -  "Repeated locks using, recursive scenario",
 -  test_005_006_setup,
 +  "Testing Binary Semaphores special case",
    NULL,
 +  test_005_006_teardown,
    test_005_006_execute
  };
 -#endif /* CH_CFG_USE_MUTEXES_RECURSIVE */
 -
 -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 -/**
 - * @page test_005_007 [5.7] Condition Variable signal test
 - *
 - * <h2>Description</h2>
 - * Five threads take a mutex and then enter a conditional variable
 - * queue, the tester thread then proceeds to signal the conditional
 - * variable five times atomically.<br> The test expects the threads to
 - * reach their goal in increasing priority order regardless of the
 - * initial order.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_CONDVARS
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [5.7.1] Starting the five threads with increasing priority, the
 - *   threads will queue on the condition variable.
 - * - [5.7.2] Atomically signaling the condition variable five times
 - *   then waiting for the threads to terminate in priority order, the
 - *   order is tested.
 - * .
 - */
 -
 -static void test_005_007_setup(void) {
 -  chCondObjectInit(&c1);
 -  chMtxObjectInit(&m1);
 -}
 -
 -static void test_005_007_execute(void) {
 -
 -  /* [5.7.1] Starting the five threads with increasing priority, the
 -     threads will queue on the condition variable.*/
 -  test_set_step(1);
 -  {
 -    tprio_t prio = chThdGetPriorityX();
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B");
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A");
 -  }
 -
 -  /* [5.7.2] Atomically signaling the condition variable five times
 -     then waiting for the threads to terminate in priority order, the
 -     order is tested.*/
 -  test_set_step(2);
 -  {
 -    chSysLock();
 -    chCondSignalI(&c1);
 -    chCondSignalI(&c1);
 -    chCondSignalI(&c1);
 -    chCondSignalI(&c1);
 -    chCondSignalI(&c1);
 -    chSchRescheduleS();
 -    chSysUnlock();
 -    test_wait_threads();
 -    test_assert_sequence("ABCDE", "invalid sequence");
 -  }
 -}
 -
 -static const testcase_t test_005_007 = {
 -  "Condition Variable signal test",
 -  test_005_007_setup,
 -  NULL,
 -  test_005_007_execute
 -};
 -#endif /* CH_CFG_USE_CONDVARS */
 -
 -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 -/**
 - * @page test_005_008 [5.8] Condition Variable broadcast test
 - *
 - * <h2>Description</h2>
 - * Five threads take a mutex and then enter a conditional variable
 - * queue, the tester thread then proceeds to broadcast the conditional
 - * variable.<br> The test expects the threads to reach their goal in
 - * increasing priority order regardless of the initial order.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_CONDVARS
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [5.8.1] Starting the five threads with increasing priority, the
 - *   threads will queue on the condition variable.
 - * - [5.8.2] Broarcasting on the condition variable then waiting for
 - *   the threads to terminate in priority order, the order is tested.
 - * .
 - */
 -
 -static void test_005_008_setup(void) {
 -  chCondObjectInit(&c1);
 -  chMtxObjectInit(&m1);
 -}
 -
 -static void test_005_008_execute(void) {
 -
 -  /* [5.8.1] Starting the five threads with increasing priority, the
 -     threads will queue on the condition variable.*/
 -  test_set_step(1);
 -  {
 -    tprio_t prio = chThdGetPriorityX();
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E");
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D");
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C");
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B");
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A");
 -  }
 -
 -  /* [5.8.2] Broarcasting on the condition variable then waiting for
 -     the threads to terminate in priority order, the order is tested.*/
 -  test_set_step(2);
 -  {
 -    chCondBroadcast(&c1);
 -    test_wait_threads();
 -    test_assert_sequence("ABCDE", "invalid sequence");
 -  }
 -}
 -
 -static const testcase_t test_005_008 = {
 -  "Condition Variable broadcast test",
 -  test_005_008_setup,
 -  NULL,
 -  test_005_008_execute
 -};
 -#endif /* CH_CFG_USE_CONDVARS */
 -
 -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 -/**
 - * @page test_005_009 [5.9] Condition Variable priority boost test
 - *
 - * <h2>Description</h2>
 - * This test case verifies the priority boost of a thread waiting on a
 - * conditional variable queue. It tests this very specific situation in
 - * order to improve code coverage. The created threads perform the
 - * following operations: TA{lock(M2), lock(M1), wait(C1), unlock(M1),
 - * unlock(M2)}, TB{lock(M2), wait(C1), unlock(M2)}. TC{lock(M1),
 - * unlock(M1)}.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_CONDVARS
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [5.9.1] Reading current base priority.
 - * - [5.9.2] Thread A is created at priority P(+1), it locks M2, locks
 - *   M1 and goes to wait on C1.
 - * - [5.9.3] Thread C is created at priority P(+2), it enqueues on M1
 - *   and boosts TA priority at P(+2).
 - * - [5.9.4] Thread B is created at priority P(+3), it enqueues on M2
 - *   and boosts TA priority at P(+3).
 - * - [5.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to
 - *   P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and
 - *   priority goes to P(+1). TC waits on C1. TA completes.
 - * - [5.9.6] Signaling C1: TC wakes up, unlocks M1 and completes.
 - * - [5.9.7] Checking the order of operations.
 - * .
 - */
 -
 -static void test_005_009_setup(void) {
 -  chCondObjectInit(&c1);
 -  chMtxObjectInit(&m1);
 -  chMtxObjectInit(&m2);
 -}
 -
 -static void test_005_009_execute(void) {
 -  tprio_t prio;
 -
 -  /* [5.9.1] Reading current base priority.*/
 -  test_set_step(1);
 -  {
 -    prio = chThdGetPriorityX();
 -  }
 -
 -  /* [5.9.2] Thread A is created at priority P(+1), it locks M2, locks
 -     M1 and goes to wait on C1.*/
 -  test_set_step(2);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread8, "A");
 -  }
 -
 -  /* [5.9.3] Thread C is created at priority P(+2), it enqueues on M1
 -     and boosts TA priority at P(+2).*/
 -  test_set_step(3);
 -  {
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "C");
 -  }
 -
 -  /* [5.9.4] Thread B is created at priority P(+3), it enqueues on M2
 -     and boosts TA priority at P(+3).*/
 -  test_set_step(4);
 -  {
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread9, "B");
 -  }
 -
 -  /* [5.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to
 -     P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and
 -     priority goes to P(+1). TC waits on C1. TA completes.*/
 -  test_set_step(5);
 -  {
 -    chCondSignal(&c1);
 -  }
 -
 -  /* [5.9.6] Signaling C1: TC wakes up, unlocks M1 and completes.*/
 -  test_set_step(6);
 -  {
 -    chCondSignal(&c1);
 -  }
 -
 -  /* [5.9.7] Checking the order of operations.*/
 -  test_set_step(7);
 -  {
 -    test_wait_threads();
 -    test_assert_sequence("ABC", "invalid sequence");
 -  }
 -}
 -
 -static const testcase_t test_005_009 = {
 -  "Condition Variable priority boost test",
 -  test_005_009_setup,
 -  NULL,
 -  test_005_009_execute
 -};
 -#endif /* CH_CFG_USE_CONDVARS */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Mutexes, Condition Variables and Priority Inheritance.
 + * @brief   Counter and Binary Semaphores.
   */
  const testcase_t * const test_sequence_005[] = {
    &test_005_001,
 -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
    &test_005_002,
 -#endif
 -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
    &test_005_003,
 -#endif
    &test_005_004,
 -#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
    &test_005_005,
 -#endif
 -#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
    &test_005_006,
 -#endif
 -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 -  &test_005_007,
 -#endif
 -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 -  &test_005_008,
 -#endif
 -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 -  &test_005_009,
 -#endif
    NULL
  };
 -#endif /* CH_CFG_USE_MUTEXES */
 +#endif /* CH_CFG_USE_SEMAPHORES */
 diff --git a/test/rt/source/test/test_sequence_006.c b/test/rt/source/test/test_sequence_006.c index 509a3a465..4c7ad2e52 100644 --- a/test/rt/source/test/test_sequence_006.c +++ b/test/rt/source/test/test_sequence_006.c @@ -22,102 +22,1048 @@   * @file    test_sequence_006.c
   * @brief   Test Sequence 006 code.
   *
 - * @page test_sequence_006 [6] Synchronous Messages
 + * @page test_sequence_006 [6] Mutexes, Condition Variables and Priority Inheritance
   *
   * File: @ref test_sequence_006.c
   *
   * <h2>Description</h2>
 - * This module implements the test sequence for the Synchronous
 - * Messages subsystem.
 + * This sequence tests the ChibiOS/RT functionalities related to
 + * mutexes, condition variables and priority inheritance algorithm.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MESSAGES
 + * - CH_CFG_USE_MUTEXES
   * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_006_001
 + * - @subpage test_006_002
 + * - @subpage test_006_003
 + * - @subpage test_006_004
 + * - @subpage test_006_005
 + * - @subpage test_006_006
 + * - @subpage test_006_007
 + * - @subpage test_006_008
 + * - @subpage test_006_009
   * .
   */
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -static THD_FUNCTION(msg_thread1, p) {
 +static MUTEX_DECL(m1);
 +static MUTEX_DECL(m2);
 +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
 +static CONDVAR_DECL(c1);
 +#endif
 -  chMsgSend(p, 'A');
 -  chMsgSend(p, 'B');
 -  chMsgSend(p, 'C');
 -  chMsgSend(p, 'D');
 +#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
 +/**
 + * @brief   CPU pulse.
 + * @note    The current implementation is not totally reliable.
 + *
 + * @param[in] duration      CPU pulse duration in milliseconds
 + */
 +void test_cpu_pulse(unsigned duration) {
 +  systime_t start, end, now;
 +
 +  start = chThdGetTicksX(chThdGetSelfX());
 +  end = start + MS2ST(duration);
 +  do {
 +    now = chThdGetTicksX(chThdGetSelfX());
 +#if defined(SIMULATOR)
 +    _sim_check_for_interrupts();
 +#endif
 +  }
 +  while (chVTIsTimeWithinX(now, start, end));
 +}
 +#endif /* CH_DBG_THREADS_PROFILING */
 +
 +static THD_FUNCTION(thread1, p) {
 +
 +  chMtxLock(&m1);
 +  test_emit_token(*(char *)p);
 +  chMtxUnlock(&m1);
 +}
 +
 +#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
 +/* Low priority thread */
 +static THD_FUNCTION(thread2L, p) {
 +
 +  (void)p;
 +  chMtxLock(&m1);
 +  test_cpu_pulse(40);
 +  chMtxUnlock(&m1);
 +  test_cpu_pulse(10);
 +  test_emit_token('C');
 +}
 +
 +/* Medium priority thread */
 +static THD_FUNCTION(thread2M, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(20);
 +  test_cpu_pulse(40);
 +  test_emit_token('B');
 +}
 +
 +/* High priority thread */
 +static THD_FUNCTION(thread2H, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(40);
 +  chMtxLock(&m1);
 +  test_cpu_pulse(10);
 +  chMtxUnlock(&m1);
 +  test_emit_token('A');
 +}
 +
 +/* Lowest priority thread */
 +static THD_FUNCTION(thread3LL, p) {
 +
 +  (void)p;
 +  chMtxLock(&m1);
 +  test_cpu_pulse(30);
 +  chMtxUnlock(&m1);
 +  test_emit_token('E');
 +}
 +
 +/* Low priority thread */
 +static THD_FUNCTION(thread3L, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(10);
 +  chMtxLock(&m2);
 +  test_cpu_pulse(20);
 +  chMtxLock(&m1);
 +  test_cpu_pulse(10);
 +  chMtxUnlock(&m1);
 +  test_cpu_pulse(10);
 +  chMtxUnlock(&m2);
 +  test_emit_token('D');
 +}
 +
 +/* Medium priority thread */
 +static THD_FUNCTION(thread3M, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(20);
 +  chMtxLock(&m2);
 +  test_cpu_pulse(10);
 +  chMtxUnlock(&m2);
 +  test_emit_token('C');
 +}
 +
 +/* High priority thread */
 +static THD_FUNCTION(thread3H, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(40);
 +  test_cpu_pulse(20);
 +  test_emit_token('B');
 +}
 +
 +/* Highest priority thread */
 +static THD_FUNCTION(thread3HH, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(50);
 +  chMtxLock(&m2);
 +  test_cpu_pulse(10);
 +  chMtxUnlock(&m2);
 +  test_emit_token('A');
 +}
 +#endif /* CH_DBG_THREADS_PROFILING */
 +
 +static THD_FUNCTION(thread4A, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(50);
 +  chMtxLock(&m1);
 +  chMtxUnlock(&m1);
 +}
 +
 +static THD_FUNCTION(thread4B, p) {
 +
 +  (void)p;
 +  chThdSleepMilliseconds(150);
 +  chSysLock();
 +  chMtxLockS(&m2);   /* For coverage of the chMtxLockS() function variant.*/
 +  chMtxUnlockS(&m2); /* For coverage of the chMtxUnlockS() function variant.*/
 +  chSchRescheduleS();
 +  chSysUnlock();
 +}
 +
 +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
 +static THD_FUNCTION(thread6, p) {
 +
 +  chMtxLock(&m1);
 +  chCondWait(&c1);
 +  test_emit_token(*(char *)p);
 +  chMtxUnlock(&m1);
 +}
 +
 +static THD_FUNCTION(thread8, p) {
 +
 +  chMtxLock(&m2);
 +  chMtxLock(&m1);
 +#if CH_CFG_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__)
 +  chCondWaitTimeout(&c1, TIME_INFINITE);
 +#else
 +  chCondWait(&c1);
 +#endif
 +  test_emit_token(*(char *)p);
 +  chMtxUnlock(&m1);
 +  chMtxUnlock(&m2);
  }
 +static THD_FUNCTION(thread9, p) {
 +
 +  chMtxLock(&m2);
 +  test_emit_token(*(char *)p);
 +  chMtxUnlock(&m2);
 +}
 +#endif /* CH_CFG_USE_CONDVARS */
 +
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_006_001 [6.1] Messages Server loop
 + * @page test_006_001 [6.1] Priority enqueuing test
   *
   * <h2>Description</h2>
 - * A messenger thread is spawned that sends four messages back to the
 - * tester thread.<br> The test expect to receive the messages in the
 - * correct sequence and to not find a fifth message waiting.
 + * Five threads, with increasing priority, are enqueued on a locked
 + * mutex then the mutex is unlocked. The test expects the threads to
 + * perform their operations in increasing priority order regardless of
 + * the initial order.
   *
   * <h2>Test Steps</h2>
 - * - [6.1.1] Starting the messenger thread.
 - * - [6.1.2] Waiting for four messages then testing the receive order.
 + * - [6.1.1] Getting the initial priority.
 + * - [6.1.2] Locking the mutex.
 + * - [6.1.3] Five threads are created that try to lock and unlock the
 + *   mutex then terminate. The threads are created in ascending
 + *   priority order.
 + * - [6.1.4] Unlocking the mutex, the threads will wakeup in priority
 + *   order because the mutext queue is an ordered one.
   * .
   */
 +static void test_006_001_setup(void) {
 +  chMtxObjectInit(&m1);
 +}
 +
  static void test_006_001_execute(void) {
 -  thread_t *tp;
 -  msg_t msg;
 +  tprio_t prio;
 -  /* [6.1.1] Starting the messenger thread.*/
 +  /* [6.1.1] Getting the initial priority.*/
    test_set_step(1);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
 -                                   msg_thread1, chThdGetSelfX());
 +    prio = chThdGetPriorityX();
    }
 -  /* [6.1.2] Waiting for four messages then testing the receive
 -     order.*/
 +  /* [6.1.2] Locking the mutex.*/
    test_set_step(2);
    {
 -    unsigned i;
 +    chMtxLock(&m1);
 +  }
 -    for (i = 0; i < 4; i++) {
 -      tp = chMsgWait();
 -      msg = chMsgGet(tp);
 -      chMsgRelease(tp, msg);
 -      test_emit_token(msg);
 -    }
 +  /* [6.1.3] Five threads are created that try to lock and unlock the
 +     mutex then terminate. The threads are created in ascending
 +     priority order.*/
 +  test_set_step(3);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread1, "E");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread1, "D");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread1, "C");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread1, "B");
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread1, "A");
 +  }
 +
 +  /* [6.1.4] Unlocking the mutex, the threads will wakeup in priority
 +     order because the mutext queue is an ordered one.*/
 +  test_set_step(4);
 +  {
 +    chMtxUnlock(&m1);
      test_wait_threads();
 -    test_assert_sequence("ABCD", "invalid sequence");
 +    test_assert(prio == chThdGetPriorityX(), "wrong priority level");
 +    test_assert_sequence("ABCDE", "invalid sequence");
    }
  }
  static const testcase_t test_006_001 = {
 -  "Messages Server loop",
 -  NULL,
 +  "Priority enqueuing test",
 +  test_006_001_setup,
    NULL,
    test_006_001_execute
  };
 +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_002 [6.2] Priority inheritance, simple case
 + *
 + * <h2>Description</h2>
 + * Three threads are involved in the classic priority inversion
 + * scenario, a medium priority thread tries to starve an high priority
 + * thread by blocking a low priority thread into a mutex lock zone. The
 + * test expects the threads to reach their goal in increasing priority
 + * order by rearranging their priorities in order to avoid the priority
 + * inversion trap.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_DBG_THREADS_PROFILING
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.2.1] Getting the system time for test duration measurement.
 + * - [6.2.2] The three contenders threads are created and let run
 + *   atomically, the goals sequence is tested, the threads must
 + *   complete in priority order.
 + * - [6.2.3] Testing that all threads completed within the specified
 + *   time windows (100mS...100mS+ALLOWED_DELAY).
 + * .
 + */
 +
 +static void test_006_002_setup(void) {
 +  chMtxObjectInit(&m1);
 +}
 +
 +static void test_006_002_execute(void) {
 +  systime_t time;
 +
 +  /* [6.2.1] Getting the system time for test duration measurement.*/
 +  test_set_step(1);
 +  {
 +    time = test_wait_tick();
 +  }
 +
 +  /* [6.2.2] The three contenders threads are created and let run
 +     atomically, the goals sequence is tested, the threads must
 +     complete in priority order.*/
 +  test_set_step(2);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread2H, 0);
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, thread2M, 0);
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread2L, 0);
 +    test_wait_threads();
 +    test_assert_sequence("ABC", "invalid sequence");
 +  }
 +
 +  /* [6.2.3] Testing that all threads completed within the specified
 +     time windows (100mS...100mS+ALLOWED_DELAY).*/
 +  test_set_step(3);
 +  {
 +    test_assert_time_window(time + MS2ST(100), time + MS2ST(100) + ALLOWED_DELAY,
 +                            "out of time window");
 +  }
 +}
 +
 +static const testcase_t test_006_002 = {
 +  "Priority inheritance, simple case",
 +  test_006_002_setup,
 +  NULL,
 +  test_006_002_execute
 +};
 +#endif /* CH_DBG_THREADS_PROFILING */
 +
 +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_003 [6.3] Priority inheritance, complex case
 + *
 + * <h2>Description</h2>
 + * Five threads are involved in the complex priority inversion
 + * scenario, the priority inheritance algorithm is tested for depths
 + * greater than one. The test expects the threads to perform their
 + * operations in increasing priority order by rearranging their
 + * priorities in order to avoid the priority inversion trap.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_DBG_THREADS_PROFILING
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.3.1] Getting the system time for test duration measurement.
 + * - [6.3.2] The five contenders threads are created and let run
 + *   atomically, the goals sequence is tested, the threads must
 + *   complete in priority order.
 + * - [6.3.3] Testing that all threads completed within the specified
 + *   time windows (110mS...110mS+ALLOWED_DELAY).
 + * .
 + */
 +
 +static void test_006_003_setup(void) {
 +  chMtxObjectInit(&m1); /* Mutex B.*/
 +  chMtxObjectInit(&m2); /* Mutex A.*/
 +}
 +
 +static void test_006_003_execute(void) {
 +  systime_t time;
 +
 +  /* [6.3.1] Getting the system time for test duration measurement.*/
 +  test_set_step(1);
 +  {
 +    time = test_wait_tick();
 +  }
 +
 +  /* [6.3.2] The five contenders threads are created and let run
 +     atomically, the goals sequence is tested, the threads must
 +     complete in priority order.*/
 +  test_set_step(2);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread3LL, 0);
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread3L, 0);
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread3M, 0);
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread3H, 0);
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread3HH, 0);
 +    test_wait_threads();
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +  }
 +
 +  /* [6.3.3] Testing that all threads completed within the specified
 +     time windows (110mS...110mS+ALLOWED_DELAY).*/
 +  test_set_step(3);
 +  {
 +    test_assert_time_window(time + MS2ST(110), time + MS2ST(110) + ALLOWED_DELAY,
 +                            "out of time window");
 +  }
 +}
 +
 +static const testcase_t test_006_003 = {
 +  "Priority inheritance, complex case",
 +  test_006_003_setup,
 +  NULL,
 +  test_006_003_execute
 +};
 +#endif /* CH_DBG_THREADS_PROFILING */
 +
 +/**
 + * @page test_006_004 [6.4] Priority return verification
 + *
 + * <h2>Description</h2>
 + * Two threads are spawned that try to lock the mutexes already locked
 + * by the tester thread with precise timing. The test expects that the
 + * priority changes caused by the priority inheritance algorithm happen
 + * at the right moment and with the right values.<br> Thread A performs
 + * wait(50), lock(m1), unlock(m1), exit. Thread B performs wait(150),
 + * lock(m2), unlock(m2), exit.
 + *
 + * <h2>Test Steps</h2>
 + * - [6.4.1] Getting current thread priority P(0) and assigning to the
 + *   threads A and B priorities +1 and +2.
 + * - [6.4.2] Spawning threads A and B at priorities P(A) and P(B).
 + * - [6.4.3] Locking the mutex M1 before thread A has a chance to lock
 + *   it. The priority must not change because A has not yet reached
 + *   chMtxLock(M1). the mutex is not locked.
 + * - [6.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and
 + *   get the mutex. This must boost the priority of the current thread
 + *   at the same level of thread A.
 + * - [6.4.5] Locking the mutex M2 before thread B has a chance to lock
 + *   it. The priority must not change because B has not yet reached
 + *   chMtxLock(M2). the mutex is not locked.
 + * - [6.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and
 + *   get the mutex. This must boost the priority of the current thread
 + *   at the same level of thread B.
 + * - [6.4.7] Unlocking M2, the priority should fall back to P(A).
 + * - [6.4.8] Unlocking M1, the priority should fall back to P(0).
 + * .
 + */
 +
 +static void test_006_004_setup(void) {
 +  chMtxObjectInit(&m1);
 +  chMtxObjectInit(&m2);
 +}
 +
 +static void test_006_004_teardown(void) {
 +  test_wait_threads();
 +}
 +
 +static void test_006_004_execute(void) {
 +  tprio_t p, pa, pb;
 +
 +  /* [6.4.1] Getting current thread priority P(0) and assigning to the
 +     threads A and B priorities +1 and +2.*/
 +  test_set_step(1);
 +  {
 +    p = chThdGetPriorityX();
 +    pa = p + 1;
 +    pb = p + 2;
 +  }
 +
 +  /* [6.4.2] Spawning threads A and B at priorities P(A) and P(B).*/
 +  test_set_step(2);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, pa, thread4A, "A");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, pb, thread4B, "B");
 +  }
 +
 +  /* [6.4.3] Locking the mutex M1 before thread A has a chance to lock
 +     it. The priority must not change because A has not yet reached
 +     chMtxLock(M1). the mutex is not locked.*/
 +  test_set_step(3);
 +  {
 +    chMtxLock(&m1);
 +    test_assert(chThdGetPriorityX() == p, "wrong priority level");
 +  }
 +
 +  /* [6.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and
 +     get the mutex. This must boost the priority of the current thread
 +     at the same level of thread A.*/
 +  test_set_step(4);
 +  {
 +    chThdSleepMilliseconds(100);
 +    test_assert(chThdGetPriorityX() == pa, "wrong priority level");
 +  }
 +
 +  /* [6.4.5] Locking the mutex M2 before thread B has a chance to lock
 +     it. The priority must not change because B has not yet reached
 +     chMtxLock(M2). the mutex is not locked.*/
 +  test_set_step(5);
 +  {
 +    chMtxLock(&m2);
 +    test_assert(chThdGetPriorityX() == pa, "wrong priority level");
 +  }
 +
 +  /* [6.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and
 +     get the mutex. This must boost the priority of the current thread
 +     at the same level of thread B.*/
 +  test_set_step(6);
 +  {
 +    chThdSleepMilliseconds(100);
 +    test_assert(chThdGetPriorityX() == pb, "wrong priority level");
 +  }
 +
 +  /* [6.4.7] Unlocking M2, the priority should fall back to P(A).*/
 +  test_set_step(7);
 +  {
 +    chMtxUnlock(&m2);
 +    test_assert(chThdGetPriorityX() == pa, "wrong priority level");
 +  }
 +
 +  /* [6.4.8] Unlocking M1, the priority should fall back to P(0).*/
 +  test_set_step(8);
 +  {
 +    chMtxUnlock(&m1);
 +    test_assert(chThdGetPriorityX() == p, "wrong priority level");
 +  }
 +}
 +
 +static const testcase_t test_006_004 = {
 +  "Priority return verification",
 +  test_006_004_setup,
 +  test_006_004_teardown,
 +  test_006_004_execute
 +};
 +
 +#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_005 [6.5] Repeated locks, non recursive scenario
 + *
 + * <h2>Description</h2>
 + * The behavior of multiple mutex locks from the same thread is tested
 + * when recursion is disabled.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - !CH_CFG_USE_MUTEXES_RECURSIVE
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.5.1] Getting current thread priority for later checks.
 + * - [6.5.2] Locking the mutex first time, it must be possible because
 + *   it is not owned.
 + * - [6.5.3] Locking the mutex second time, it must fail because it is
 + *   already owned.
 + * - [6.5.4] Unlocking the mutex then it must not be owned anymore and
 + *   the queue must be empty.
 + * - [6.5.5] Testing that priority has not changed after operations.
 + * - [6.5.6] Testing chMtxUnlockAll() behavior.
 + * - [6.5.7] Testing that priority has not changed after operations.
 + * .
 + */
 +
 +static void test_006_005_setup(void) {
 +  chMtxObjectInit(&m1);
 +}
 +
 +static void test_006_005_execute(void) {
 +  bool b;
 +  tprio_t prio;
 +
 +  /* [6.5.1] Getting current thread priority for later checks.*/
 +  test_set_step(1);
 +  {
 +    prio = chThdGetPriorityX();
 +  }
 +
 +  /* [6.5.2] Locking the mutex first time, it must be possible because
 +     it is not owned.*/
 +  test_set_step(2);
 +  {
 +    b = chMtxTryLock(&m1);
 +    test_assert(b, "already locked");
 +  }
 +
 +  /* [6.5.3] Locking the mutex second time, it must fail because it is
 +     already owned.*/
 +  test_set_step(3);
 +  {
 +    b = chMtxTryLock(&m1);
 +    test_assert(!b, "not locked");
 +  }
 +
 +  /* [6.5.4] Unlocking the mutex then it must not be owned anymore and
 +     the queue must be empty.*/
 +  test_set_step(4);
 +  {
 +    chMtxUnlock(&m1);
 +    test_assert(m1.owner == NULL, "still owned");
 +    test_assert(queue_isempty(&m1.queue), "queue not empty");
 +  }
 +
 +  /* [6.5.5] Testing that priority has not changed after operations.*/
 +  test_set_step(5);
 +  {
 +    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 +  }
 +
 +  /* [6.5.6] Testing chMtxUnlockAll() behavior.*/
 +  test_set_step(6);
 +  {
 +    b = chMtxTryLock(&m1);
 +    test_assert(b, "already locked");
 +    b = chMtxTryLock(&m1);
 +    test_assert(!b, "not locked");
 +
 +    chMtxUnlockAll();
 +    test_assert(m1.owner == NULL, "still owned");
 +    test_assert(queue_isempty(&m1.queue), "queue not empty");
 +  }
 +
 +  /* [6.5.7] Testing that priority has not changed after operations.*/
 +  test_set_step(7);
 +  {
 +    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 +  }
 +}
 +
 +static const testcase_t test_006_005 = {
 +  "Repeated locks, non recursive scenario",
 +  test_006_005_setup,
 +  NULL,
 +  test_006_005_execute
 +};
 +#endif /* !CH_CFG_USE_MUTEXES_RECURSIVE */
 +
 +#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_006 [6.6] Repeated locks using, recursive scenario
 + *
 + * <h2>Description</h2>
 + * The behavior of multiple mutex locks from the same thread is tested
 + * when recursion is enabled.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_MUTEXES_RECURSIVE
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.6.1] Getting current thread priority for later checks.
 + * - [6.6.2] Locking the mutex first time, it must be possible because
 + *   it is not owned.
 + * - [6.6.3] Locking the mutex second time, it must be possible because
 + *   it is recursive.
 + * - [6.6.4] Unlocking the mutex then it must be still owned because
 + *   recursivity.
 + * - [6.6.5] Unlocking the mutex then it must not be owned anymore and
 + *   the queue must be empty.
 + * - [6.6.6] Testing that priority has not changed after operations.
 + * - [6.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls
 + *   and a final chMtxUnlockAllS().
 + * - [6.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a
 + *   final chMtxUnlockAll().
 + * - [6.6.9] Testing that priority has not changed after operations.
 + * .
 + */
 +
 +static void test_006_006_setup(void) {
 +  chMtxObjectInit(&m1);
 +}
 +
 +static void test_006_006_execute(void) {
 +  bool b;
 +  tprio_t prio;
 +
 +  /* [6.6.1] Getting current thread priority for later checks.*/
 +  test_set_step(1);
 +  {
 +    prio = chThdGetPriorityX();
 +  }
 +
 +  /* [6.6.2] Locking the mutex first time, it must be possible because
 +     it is not owned.*/
 +  test_set_step(2);
 +  {
 +    b = chMtxTryLock(&m1);
 +    test_assert(b, "already locked");
 +  }
 +
 +  /* [6.6.3] Locking the mutex second time, it must be possible because
 +     it is recursive.*/
 +  test_set_step(3);
 +  {
 +    b = chMtxTryLock(&m1);
 +    test_assert(b, "already locked");
 +  }
 +
 +  /* [6.6.4] Unlocking the mutex then it must be still owned because
 +     recursivity.*/
 +  test_set_step(4);
 +  {
 +    chMtxUnlock(&m1);
 +    test_assert(m1.owner != NULL, "not owned");
 +  }
 +
 +  /* [6.6.5] Unlocking the mutex then it must not be owned anymore and
 +     the queue must be empty.*/
 +  test_set_step(5);
 +  {
 +    chMtxUnlock(&m1);
 +    test_assert(m1.owner == NULL, "still owned");
 +    test_assert(queue_isempty(&m1.queue), "queue not empty");
 +  }
 +
 +  /* [6.6.6] Testing that priority has not changed after operations.*/
 +  test_set_step(6);
 +  {
 +    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 +  }
 +
 +  /* [6.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls
 +     and a final chMtxUnlockAllS().*/
 +  test_set_step(7);
 +  {
 +    b = chMtxTryLock(&m1);
 +    test_assert(b, "already locked");
 +    chSysLock();
 +    b = chMtxTryLockS(&m1);
 +    chSysUnlock();
 +    test_assert(b, "already locked");
 +    test_assert(m1.cnt == 2, "invalid recursion counter");
 +    chSysLock();
 +    chMtxUnlockAllS();
 +    chSysUnlock();
 +    test_assert(m1.owner == NULL, "still owned");
 +    test_assert(queue_isempty(&m1.queue), "queue not empty");
 +    test_assert(m1.cnt == 0, "invalid recursion counter");
 +  }
 +
 +  /* [6.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a
 +     final chMtxUnlockAll().*/
 +  test_set_step(8);
 +  {
 +    chMtxLock(&m1);
 +    test_assert(m1.owner != NULL, "not owned");
 +    chSysLock();
 +    chMtxLockS(&m1);
 +    chSysUnlock();
 +    test_assert(m1.owner != NULL, "not owned");
 +    test_assert(m1.cnt == 2, "invalid recursion counter");
 +    chMtxUnlockAll();
 +    test_assert(m1.owner == NULL, "still owned");
 +    test_assert(queue_isempty(&m1.queue), "queue not empty");
 +    test_assert(m1.cnt == 0, "invalid recursion counter");
 +  }
 +
 +  /* [6.6.9] Testing that priority has not changed after operations.*/
 +  test_set_step(9);
 +  {
 +    test_assert(chThdGetPriorityX() == prio, "wrong priority level");
 +  }
 +}
 +
 +static const testcase_t test_006_006 = {
 +  "Repeated locks using, recursive scenario",
 +  test_006_006_setup,
 +  NULL,
 +  test_006_006_execute
 +};
 +#endif /* CH_CFG_USE_MUTEXES_RECURSIVE */
 +
 +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_007 [6.7] Condition Variable signal test
 + *
 + * <h2>Description</h2>
 + * Five threads take a mutex and then enter a conditional variable
 + * queue, the tester thread then proceeds to signal the conditional
 + * variable five times atomically.<br> The test expects the threads to
 + * reach their goal in increasing priority order regardless of the
 + * initial order.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_CONDVARS
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.7.1] Starting the five threads with increasing priority, the
 + *   threads will queue on the condition variable.
 + * - [6.7.2] Atomically signaling the condition variable five times
 + *   then waiting for the threads to terminate in priority order, the
 + *   order is tested.
 + * .
 + */
 +
 +static void test_006_007_setup(void) {
 +  chCondObjectInit(&c1);
 +  chMtxObjectInit(&m1);
 +}
 +
 +static void test_006_007_execute(void) {
 +
 +  /* [6.7.1] Starting the five threads with increasing priority, the
 +     threads will queue on the condition variable.*/
 +  test_set_step(1);
 +  {
 +    tprio_t prio = chThdGetPriorityX();
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B");
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A");
 +  }
 +
 +  /* [6.7.2] Atomically signaling the condition variable five times
 +     then waiting for the threads to terminate in priority order, the
 +     order is tested.*/
 +  test_set_step(2);
 +  {
 +    chSysLock();
 +    chCondSignalI(&c1);
 +    chCondSignalI(&c1);
 +    chCondSignalI(&c1);
 +    chCondSignalI(&c1);
 +    chCondSignalI(&c1);
 +    chSchRescheduleS();
 +    chSysUnlock();
 +    test_wait_threads();
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +  }
 +}
 +
 +static const testcase_t test_006_007 = {
 +  "Condition Variable signal test",
 +  test_006_007_setup,
 +  NULL,
 +  test_006_007_execute
 +};
 +#endif /* CH_CFG_USE_CONDVARS */
 +
 +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_008 [6.8] Condition Variable broadcast test
 + *
 + * <h2>Description</h2>
 + * Five threads take a mutex and then enter a conditional variable
 + * queue, the tester thread then proceeds to broadcast the conditional
 + * variable.<br> The test expects the threads to reach their goal in
 + * increasing priority order regardless of the initial order.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_CONDVARS
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.8.1] Starting the five threads with increasing priority, the
 + *   threads will queue on the condition variable.
 + * - [6.8.2] Broarcasting on the condition variable then waiting for
 + *   the threads to terminate in priority order, the order is tested.
 + * .
 + */
 +
 +static void test_006_008_setup(void) {
 +  chCondObjectInit(&c1);
 +  chMtxObjectInit(&m1);
 +}
 +
 +static void test_006_008_execute(void) {
 +
 +  /* [6.8.1] Starting the five threads with increasing priority, the
 +     threads will queue on the condition variable.*/
 +  test_set_step(1);
 +  {
 +    tprio_t prio = chThdGetPriorityX();
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E");
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D");
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C");
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B");
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A");
 +  }
 +
 +  /* [6.8.2] Broarcasting on the condition variable then waiting for
 +     the threads to terminate in priority order, the order is tested.*/
 +  test_set_step(2);
 +  {
 +    chCondBroadcast(&c1);
 +    test_wait_threads();
 +    test_assert_sequence("ABCDE", "invalid sequence");
 +  }
 +}
 +
 +static const testcase_t test_006_008 = {
 +  "Condition Variable broadcast test",
 +  test_006_008_setup,
 +  NULL,
 +  test_006_008_execute
 +};
 +#endif /* CH_CFG_USE_CONDVARS */
 +
 +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 +/**
 + * @page test_006_009 [6.9] Condition Variable priority boost test
 + *
 + * <h2>Description</h2>
 + * This test case verifies the priority boost of a thread waiting on a
 + * conditional variable queue. It tests this very specific situation in
 + * order to improve code coverage. The created threads perform the
 + * following operations: TA{lock(M2), lock(M1), wait(C1), unlock(M1),
 + * unlock(M2)}, TB{lock(M2), wait(C1), unlock(M2)}. TC{lock(M1),
 + * unlock(M1)}.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_CONDVARS
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [6.9.1] Reading current base priority.
 + * - [6.9.2] Thread A is created at priority P(+1), it locks M2, locks
 + *   M1 and goes to wait on C1.
 + * - [6.9.3] Thread C is created at priority P(+2), it enqueues on M1
 + *   and boosts TA priority at P(+2).
 + * - [6.9.4] Thread B is created at priority P(+3), it enqueues on M2
 + *   and boosts TA priority at P(+3).
 + * - [6.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to
 + *   P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and
 + *   priority goes to P(+1). TC waits on C1. TA completes.
 + * - [6.9.6] Signaling C1: TC wakes up, unlocks M1 and completes.
 + * - [6.9.7] Checking the order of operations.
 + * .
 + */
 +
 +static void test_006_009_setup(void) {
 +  chCondObjectInit(&c1);
 +  chMtxObjectInit(&m1);
 +  chMtxObjectInit(&m2);
 +}
 +
 +static void test_006_009_execute(void) {
 +  tprio_t prio;
 +
 +  /* [6.9.1] Reading current base priority.*/
 +  test_set_step(1);
 +  {
 +    prio = chThdGetPriorityX();
 +  }
 +
 +  /* [6.9.2] Thread A is created at priority P(+1), it locks M2, locks
 +     M1 and goes to wait on C1.*/
 +  test_set_step(2);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread8, "A");
 +  }
 +
 +  /* [6.9.3] Thread C is created at priority P(+2), it enqueues on M1
 +     and boosts TA priority at P(+2).*/
 +  test_set_step(3);
 +  {
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "C");
 +  }
 +
 +  /* [6.9.4] Thread B is created at priority P(+3), it enqueues on M2
 +     and boosts TA priority at P(+3).*/
 +  test_set_step(4);
 +  {
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread9, "B");
 +  }
 +
 +  /* [6.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to
 +     P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and
 +     priority goes to P(+1). TC waits on C1. TA completes.*/
 +  test_set_step(5);
 +  {
 +    chCondSignal(&c1);
 +  }
 +
 +  /* [6.9.6] Signaling C1: TC wakes up, unlocks M1 and completes.*/
 +  test_set_step(6);
 +  {
 +    chCondSignal(&c1);
 +  }
 +
 +  /* [6.9.7] Checking the order of operations.*/
 +  test_set_step(7);
 +  {
 +    test_wait_threads();
 +    test_assert_sequence("ABC", "invalid sequence");
 +  }
 +}
 +
 +static const testcase_t test_006_009 = {
 +  "Condition Variable priority boost test",
 +  test_006_009_setup,
 +  NULL,
 +  test_006_009_execute
 +};
 +#endif /* CH_CFG_USE_CONDVARS */
 +
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Synchronous Messages.
 + * @brief   Mutexes, Condition Variables and Priority Inheritance.
   */
  const testcase_t * const test_sequence_006[] = {
    &test_006_001,
 +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
 +  &test_006_002,
 +#endif
 +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
 +  &test_006_003,
 +#endif
 +  &test_006_004,
 +#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
 +  &test_006_005,
 +#endif
 +#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__)
 +  &test_006_006,
 +#endif
 +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 +  &test_006_007,
 +#endif
 +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 +  &test_006_008,
 +#endif
 +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__)
 +  &test_006_009,
 +#endif
    NULL
  };
 -#endif /* CH_CFG_USE_MESSAGES */
 +#endif /* CH_CFG_USE_MUTEXES */
 diff --git a/test/rt/source/test/test_sequence_007.c b/test/rt/source/test/test_sequence_007.c index fc4c3f0ec..cf7828f90 100644 --- a/test/rt/source/test/test_sequence_007.c +++ b/test/rt/source/test/test_sequence_007.c @@ -22,56 +22,37 @@   * @file    test_sequence_007.c
   * @brief   Test Sequence 007 code.
   *
 - * @page test_sequence_007 [7] Event Sources and Event Flags
 + * @page test_sequence_007 [7] Synchronous Messages
   *
   * File: @ref test_sequence_007.c
   *
   * <h2>Description</h2>
 - * This module implements the test sequence for the Events subsystem.
 + * This module implements the test sequence for the Synchronous
 + * Messages subsystem.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_EVENTS
 + * - CH_CFG_USE_MESSAGES
   * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_007_001
 - * - @subpage test_007_002
 - * - @subpage test_007_003
 - * - @subpage test_007_004
 - * - @subpage test_007_005
 - * - @subpage test_007_006
 - * - @subpage test_007_007
   * .
   */
 -#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -static EVENTSOURCE_DECL(es1);
 -static EVENTSOURCE_DECL(es2);
 +static THD_FUNCTION(msg_thread1, p) {
 -static void h1(eventid_t id) {(void)id;test_emit_token('A');}
 -static void h2(eventid_t id) {(void)id;test_emit_token('B');}
 -static void h3(eventid_t id) {(void)id;test_emit_token('C');}
 -static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
 -
 -static THD_FUNCTION(evt_thread3, p) {
 -
 -  chThdSleepMilliseconds(50);
 -  chEvtSignal((thread_t *)p, 1);
 -}
 -
 -static THD_FUNCTION(evt_thread7, p) {
 -
 -  (void)p;
 -  chEvtBroadcast(&es1);
 -  chThdSleepMilliseconds(50);
 -  chEvtBroadcast(&es2);
 +  chMsgSend(p, 'A');
 +  chMsgSend(p, 'B');
 +  chMsgSend(p, 'C');
 +  chMsgSend(p, 'D');
  }
  /****************************************************************************
 @@ -79,491 +60,64 @@ static THD_FUNCTION(evt_thread7, p) {   ****************************************************************************/
  /**
 - * @page test_007_001 [7.1] Events registration
 + * @page test_007_001 [7.1] Messages Server loop
   *
   * <h2>Description</h2>
 - * Two event listeners are registered on an event source and then
 - * unregistered in the same order.<br> The test expects that the even
 - * source has listeners after the registrations and after the first
 - * unregistration, then, after the second unegistration, the test
 - * expects no more listeners.
 + * A messenger thread is spawned that sends four messages back to the
 + * tester thread.<br> The test expect to receive the messages in the
 + * correct sequence and to not find a fifth message waiting.
   *
   * <h2>Test Steps</h2>
 - * - [7.1.1] An Event Source is initialized.
 - * - [7.1.2] Two Event Listeners are registered on the Event Source,
 - *   the Event Source is tested to have listeners.
 - * - [7.1.3] An Event Listener is unregistered, the Event Source must
 - *   still have listeners.
 - * - [7.1.4] An Event Listener is unregistered, the Event Source must
 - *   not have listeners.
 + * - [7.1.1] Starting the messenger thread.
 + * - [7.1.2] Waiting for four messages then testing the receive order.
   * .
   */
  static void test_007_001_execute(void) {
 -  event_listener_t el1, el2;
 +  thread_t *tp;
 +  msg_t msg;
 -  /* [7.1.1] An Event Source is initialized.*/
 +  /* [7.1.1] Starting the messenger thread.*/
    test_set_step(1);
    {
 -    chEvtObjectInit(&es1);
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
 +                                   msg_thread1, chThdGetSelfX());
    }
 -  /* [7.1.2] Two Event Listeners are registered on the Event Source,
 -     the Event Source is tested to have listeners.*/
 +  /* [7.1.2] Waiting for four messages then testing the receive
 +     order.*/
    test_set_step(2);
    {
 -    chEvtRegisterMask(&es1, &el1, 1);
 -    chEvtRegisterMask(&es1, &el2, 2);
 -    test_assert_lock(chEvtIsListeningI(&es1), "no listener");
 -  }
 -
 -  /* [7.1.3] An Event Listener is unregistered, the Event Source must
 -     still have listeners.*/
 -  test_set_step(3);
 -  {
 -    chEvtUnregister(&es1, &el1);
 -    test_assert_lock(chEvtIsListeningI(&es1), "no listener");
 -  }
 +    unsigned i;
 -  /* [7.1.4] An Event Listener is unregistered, the Event Source must
 -     not have listeners.*/
 -  test_set_step(4);
 -  {
 -    chEvtUnregister(&es1, &el2);
 -    test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
 +    for (i = 0; i < 4; i++) {
 +      tp = chMsgWait();
 +      msg = chMsgGet(tp);
 +      chMsgRelease(tp, msg);
 +      test_emit_token(msg);
 +    }
 +    test_wait_threads();
 +    test_assert_sequence("ABCD", "invalid sequence");
    }
  }
  static const testcase_t test_007_001 = {
 -  "Events registration",
 +  "Messages Server loop",
    NULL,
    NULL,
    test_007_001_execute
  };
 -/**
 - * @page test_007_002 [7.2] Event Flags dispatching
 - *
 - * <h2>Description</h2>
 - * The test dispatches three event flags and verifies that the
 - * associated event handlers are invoked in LSb-first order.
 - *
 - * <h2>Test Steps</h2>
 - * - [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is
 - *   invoked, the sequence of handlers calls is tested.
 - * .
 - */
 -
 -static void test_007_002_setup(void) {
 -  chEvtGetAndClearEvents(ALL_EVENTS);
 -}
 -
 -static void test_007_002_execute(void) {
 -
 -  /* [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is
 -     invoked, the sequence of handlers calls is tested.*/
 -  test_set_step(1);
 -  {
 -    chEvtDispatch(evhndl, 7);
 -    test_assert_sequence("ABC", "invalid sequence");
 -  }
 -}
 -
 -static const testcase_t test_007_002 = {
 -  "Event Flags dispatching",
 -  test_007_002_setup,
 -  NULL,
 -  test_007_002_execute
 -};
 -
 -/**
 - * @page test_007_003 [7.3] Events Flags wait using chEvtWaitOne()
 - *
 - * <h2>Description</h2>
 - * Functionality of chEvtWaitOne() is tested under various scenarios.
 - *
 - * <h2>Test Steps</h2>
 - * - [7.3.1] Setting three event flags.
 - * - [7.3.2] Calling chEvtWaitOne() three times, each time a single
 - *   flag must be returned in order of priority.
 - * - [7.3.3] Getting current time and starting a signaler thread, the
 - *   thread will set an event flag after 50mS.
 - * - [7.3.4] Calling chEvtWaitOne() then verifying that the event has
 - *   been received after 50mS and that the event flags mask has been
 - *   emptied.
 - * .
 - */
 -
 -static void test_007_003_setup(void) {
 -  chEvtGetAndClearEvents(ALL_EVENTS);
 -}
 -
 -static void test_007_003_execute(void) {
 -  eventmask_t m;
 -  systime_t target_time;
 -
 -  /* [7.3.1] Setting three event flags.*/
 -  test_set_step(1);
 -  {
 -    chEvtAddEvents(7);
 -  }
 -
 -  /* [7.3.2] Calling chEvtWaitOne() three times, each time a single
 -     flag must be returned in order of priority.*/
 -  test_set_step(2);
 -  {
 -    m = chEvtWaitOne(ALL_EVENTS);
 -    test_assert(m == 1, "single event error");
 -    m = chEvtWaitOne(ALL_EVENTS);
 -    test_assert(m == 2, "single event error");
 -    m = chEvtWaitOne(ALL_EVENTS);
 -    test_assert(m == 4, "single event error");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -  }
 -
 -  /* [7.3.3] Getting current time and starting a signaler thread, the
 -     thread will set an event flag after 50mS.*/
 -  test_set_step(3);
 -  {
 -    target_time = test_wait_tick() + MS2ST(50);
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 -                                   evt_thread3, chThdGetSelfX());
 -  }
 -
 -  /* [7.3.4] Calling chEvtWaitOne() then verifying that the event has
 -     been received after 50mS and that the event flags mask has been
 -     emptied.*/
 -  test_set_step(4);
 -  {
 -    m = chEvtWaitOne(ALL_EVENTS);
 -    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 -                            "out of time window");
 -    test_assert(m == 1, "event flag error");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -    test_wait_threads();
 -  }
 -}
 -
 -static const testcase_t test_007_003 = {
 -  "Events Flags wait using chEvtWaitOne()",
 -  test_007_003_setup,
 -  NULL,
 -  test_007_003_execute
 -};
 -
 -/**
 - * @page test_007_004 [7.4] Events Flags wait using chEvtWaitAny()
 - *
 - * <h2>Description</h2>
 - * Functionality of chEvtWaitAny() is tested under various scenarios.
 - *
 - * <h2>Test Steps</h2>
 - * - [7.4.1] Setting two, non contiguous, event flags.
 - * - [7.4.2] Calling chEvtWaitAny() one time, the two flags must be
 - *   returned.
 - * - [7.4.3] Getting current time and starting a signaler thread, the
 - *   thread will set an event flag after 50mS.
 - * - [7.4.4] Calling chEvtWaitAny() then verifying that the event has
 - *   been received after 50mS and that the event flags mask has been
 - *   emptied.
 - * .
 - */
 -
 -static void test_007_004_setup(void) {
 -  chEvtGetAndClearEvents(ALL_EVENTS);
 -}
 -
 -static void test_007_004_execute(void) {
 -  eventmask_t m;
 -  systime_t target_time;
 -
 -  /* [7.4.1] Setting two, non contiguous, event flags.*/
 -  test_set_step(1);
 -  {
 -    chEvtAddEvents(5);
 -  }
 -
 -  /* [7.4.2] Calling chEvtWaitAny() one time, the two flags must be
 -     returned.*/
 -  test_set_step(2);
 -  {
 -    m = chEvtWaitAny(ALL_EVENTS);
 -    test_assert(m == 5, "unexpected pending bit");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -  }
 -
 -  /* [7.4.3] Getting current time and starting a signaler thread, the
 -     thread will set an event flag after 50mS.*/
 -  test_set_step(3);
 -  {
 -    target_time = test_wait_tick() + MS2ST(50);
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 -                                   evt_thread3, chThdGetSelfX());
 -  }
 -
 -  /* [7.4.4] Calling chEvtWaitAny() then verifying that the event has
 -     been received after 50mS and that the event flags mask has been
 -     emptied.*/
 -  test_set_step(4);
 -  {
 -    m = chEvtWaitAny(ALL_EVENTS);
 -    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 -                            "out of time window");
 -    test_assert(m == 1, "event flag error");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -    test_wait_threads();
 -  }
 -}
 -
 -static const testcase_t test_007_004 = {
 -  "Events Flags wait using chEvtWaitAny()",
 -  test_007_004_setup,
 -  NULL,
 -  test_007_004_execute
 -};
 -
 -/**
 - * @page test_007_005 [7.5] Events Flags wait using chEvtWaitAll()
 - *
 - * <h2>Description</h2>
 - * Functionality of chEvtWaitAll() is tested under various scenarios.
 - *
 - * <h2>Test Steps</h2>
 - * - [7.5.1] Setting two, non contiguous, event flags.
 - * - [7.5.2] Calling chEvtWaitAll() one time, the two flags must be
 - *   returned.
 - * - [7.5.3] Setting one event flag.
 - * - [7.5.4] Getting current time and starting a signaler thread, the
 - *   thread will set another event flag after 50mS.
 - * - [7.5.5] Calling chEvtWaitAll() then verifying that both event
 - *   flags have been received after 50mS and that the event flags mask
 - *   has been emptied.
 - * .
 - */
 -
 -static void test_007_005_setup(void) {
 -  chEvtGetAndClearEvents(ALL_EVENTS);
 -}
 -
 -static void test_007_005_execute(void) {
 -  eventmask_t m;
 -  systime_t target_time;
 -
 -  /* [7.5.1] Setting two, non contiguous, event flags.*/
 -  test_set_step(1);
 -  {
 -    chEvtAddEvents(5);
 -  }
 -
 -  /* [7.5.2] Calling chEvtWaitAll() one time, the two flags must be
 -     returned.*/
 -  test_set_step(2);
 -  {
 -    m = chEvtWaitAll(5);
 -    test_assert(m == 5, "unexpected pending bit");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -  }
 -
 -  /* [7.5.3] Setting one event flag.*/
 -  test_set_step(3);
 -  {
 -    chEvtAddEvents(4);
 -  }
 -
 -  /* [7.5.4] Getting current time and starting a signaler thread, the
 -     thread will set another event flag after 50mS.*/
 -  test_set_step(4);
 -  {
 -    target_time = test_wait_tick() + MS2ST(50);
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 -                                   evt_thread3, chThdGetSelfX());
 -  }
 -
 -  /* [7.5.5] Calling chEvtWaitAll() then verifying that both event
 -     flags have been received after 50mS and that the event flags mask
 -     has been emptied.*/
 -  test_set_step(5);
 -  {
 -    m = chEvtWaitAll(5);
 -    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 -                            "out of time window");
 -    test_assert(m == 5, "event flags error");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -    test_wait_threads();
 -  }
 -}
 -
 -static const testcase_t test_007_005 = {
 -  "Events Flags wait using chEvtWaitAll()",
 -  test_007_005_setup,
 -  NULL,
 -  test_007_005_execute
 -};
 -
 -#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
 -/**
 - * @page test_007_006 [7.6] Events Flags wait timeouts
 - *
 - * <h2>Description</h2>
 - * Timeout functionality is tested for chEvtWaitOneTimeout(),
 - * chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_EVENTS_TIMEOUT
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [7.6.1] The functions are invoked first with TIME_IMMEDIATE
 - *   timeout, the timeout condition is tested.
 - * - [7.6.2] The functions are invoked first with a 50mS timeout, the
 - *   timeout condition is tested.
 - * .
 - */
 -
 -static void test_007_006_setup(void) {
 -  chEvtGetAndClearEvents(ALL_EVENTS);
 -}
 -
 -static void test_007_006_execute(void) {
 -  eventmask_t m;
 -
 -  /* [7.6.1] The functions are invoked first with TIME_IMMEDIATE
 -     timeout, the timeout condition is tested.*/
 -  test_set_step(1);
 -  {
 -    m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
 -    test_assert(m == 0, "spurious event");
 -    m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
 -    test_assert(m == 0, "spurious event");
 -    m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
 -    test_assert(m == 0, "spurious event");
 -  }
 -
 -  /* [7.6.2] The functions are invoked first with a 50mS timeout, the
 -     timeout condition is tested.*/
 -  test_set_step(2);
 -  {
 -    m = chEvtWaitOneTimeout(ALL_EVENTS, MS2ST(50));
 -    test_assert(m == 0, "spurious event");
 -    m = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(50));
 -    test_assert(m == 0, "spurious event");
 -    m = chEvtWaitAllTimeout(ALL_EVENTS, MS2ST(50));
 -    test_assert(m == 0, "spurious event");
 -  }
 -}
 -
 -static const testcase_t test_007_006 = {
 -  "Events Flags wait timeouts",
 -  test_007_006_setup,
 -  NULL,
 -  test_007_006_execute
 -};
 -#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
 -
 -/**
 - * @page test_007_007 [7.7] Broadcasting using chEvtBroadcast()
 - *
 - * <h2>Description</h2>
 - * Functionality of chEvtBroadcast() is tested.
 - *
 - * <h2>Test Steps</h2>
 - * - [7.7.1] Registering on two event sources associating them with
 - *   flags 1 and 4.
 - * - [7.7.2] Getting current time and starting a broadcaster thread,
 - *   the thread broadcast the first Event Source immediately and the
 - *   other after 50mS.
 - * - [7.7.3] Calling chEvtWaitAll() then verifying that both event
 - *   flags have been received after 50mS and that the event flags mask
 - *   has been emptied.
 - * - [7.7.4] Unregistering from the Event Sources.
 - * .
 - */
 -
 -static void test_007_007_setup(void) {
 -  chEvtGetAndClearEvents(ALL_EVENTS);
 -  chEvtObjectInit(&es1);
 -  chEvtObjectInit(&es2);
 -}
 -
 -static void test_007_007_execute(void) {
 -  eventmask_t m;
 -  event_listener_t el1, el2;
 -  systime_t target_time;
 -
 -  /* [7.7.1] Registering on two event sources associating them with
 -     flags 1 and 4.*/
 -  test_set_step(1);
 -  {
 -    chEvtRegisterMask(&es1, &el1, 1);
 -    chEvtRegisterMask(&es2, &el2, 4);
 -  }
 -
 -  /* [7.7.2] Getting current time and starting a broadcaster thread,
 -     the thread broadcast the first Event Source immediately and the
 -     other after 50mS.*/
 -  test_set_step(2);
 -  {
 -    target_time = test_wait_tick() + MS2ST(50);
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 -                                   evt_thread7, "A");
 -  }
 -
 -  /* [7.7.3] Calling chEvtWaitAll() then verifying that both event
 -     flags have been received after 50mS and that the event flags mask
 -     has been emptied.*/
 -  test_set_step(3);
 -  {
 -    m = chEvtWaitAll(5);
 -    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 -                            "out of time window");
 -    m = chEvtGetAndClearEvents(ALL_EVENTS);
 -    test_assert(m == 0, "stuck event");
 -    test_wait_threads();
 -  }
 -
 -  /* [7.7.4] Unregistering from the Event Sources.*/
 -  test_set_step(4);
 -  {
 -    chEvtUnregister(&es1, &el1);
 -    chEvtUnregister(&es2, &el2);
 -    test_assert(!chEvtIsListeningI(&es1), "stuck listener");
 -    test_assert(!chEvtIsListeningI(&es2), "stuck listener");
 -  }
 -}
 -
 -static const testcase_t test_007_007 = {
 -  "Broadcasting using chEvtBroadcast()",
 -  test_007_007_setup,
 -  NULL,
 -  test_007_007_execute
 -};
 -
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Event Sources and Event Flags.
 + * @brief   Synchronous Messages.
   */
  const testcase_t * const test_sequence_007[] = {
    &test_007_001,
 -  &test_007_002,
 -  &test_007_003,
 -  &test_007_004,
 -  &test_007_005,
 -#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
 -  &test_007_006,
 -#endif
 -  &test_007_007,
    NULL
  };
 -#endif /* CH_CFG_USE_EVENTS */
 +#endif /* CH_CFG_USE_MESSAGES */
 diff --git a/test/rt/source/test/test_sequence_008.c b/test/rt/source/test/test_sequence_008.c index 349e1a9d0..bc3b222ab 100644 --- a/test/rt/source/test/test_sequence_008.c +++ b/test/rt/source/test/test_sequence_008.c @@ -22,374 +22,528 @@   * @file    test_sequence_008.c
   * @brief   Test Sequence 008 code.
   *
 - * @page test_sequence_008 [8] Mailboxes
 + * @page test_sequence_008 [8] Event Sources and Event Flags
   *
   * File: @ref test_sequence_008.c
   *
   * <h2>Description</h2>
 - * This sequence tests the ChibiOS/RT functionalities related to
 - * mailboxes.
 + * This module implements the test sequence for the Events subsystem.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MAILBOXES
 + * - CH_CFG_USE_EVENTS
   * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_008_001
   * - @subpage test_008_002
   * - @subpage test_008_003
 + * - @subpage test_008_004
 + * - @subpage test_008_005
 + * - @subpage test_008_006
 + * - @subpage test_008_007
   * .
   */
 -#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#define MB_SIZE 4
 +static EVENTSOURCE_DECL(es1);
 +static EVENTSOURCE_DECL(es2);
 -static msg_t mb_buffer[MB_SIZE];
 -static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
 +static void h1(eventid_t id) {(void)id;test_emit_token('A');}
 +static void h2(eventid_t id) {(void)id;test_emit_token('B');}
 +static void h3(eventid_t id) {(void)id;test_emit_token('C');}
 +static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
 +
 +static THD_FUNCTION(evt_thread3, p) {
 +
 +  chThdSleepMilliseconds(50);
 +  chEvtSignal((thread_t *)p, 1);
 +}
 +
 +static THD_FUNCTION(evt_thread7, p) {
 +
 +  (void)p;
 +  chEvtBroadcast(&es1);
 +  chThdSleepMilliseconds(50);
 +  chEvtBroadcast(&es2);
 +}
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_008_001 [8.1] Mailbox normal API, non-blocking tests
 + * @page test_008_001 [8.1] Events registration
   *
   * <h2>Description</h2>
 - * The mailbox normal API is tested without triggering blocking
 - * conditions.
 + * Two event listeners are registered on an event source and then
 + * unregistered in the same order.<br> The test expects that the even
 + * source has listeners after the registrations and after the first
 + * unregistration, then, after the second unegistration, the test
 + * expects no more listeners.
   *
   * <h2>Test Steps</h2>
 - * - [8.1.1] Testing the mailbox size.
 - * - [8.1.2] Resetting the mailbox, conditions are checked, no errors
 - *   expected.
 - * - [8.1.3] Testing the behavior of API when the mailbox is in reset
 - *   state then return in active state.
 - * - [8.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 - *   once, no errors expected.
 - * - [8.1.5] Testing intermediate conditions. Data pointers must be
 - *   aligned, semaphore counters are checked.
 - * - [8.1.6] Emptying the mailbox using chMBFetch(), no errors
 - *   expected.
 - * - [8.1.7] Posting and then fetching one more message, no errors
 - *   expected.
 - * - [8.1.8] Testing final conditions. Data pointers must be aligned to
 - *   buffer start, semaphore counters are checked.
 + * - [8.1.1] An Event Source is initialized.
 + * - [8.1.2] Two Event Listeners are registered on the Event Source,
 + *   the Event Source is tested to have listeners.
 + * - [8.1.3] An Event Listener is unregistered, the Event Source must
 + *   still have listeners.
 + * - [8.1.4] An Event Listener is unregistered, the Event Source must
 + *   not have listeners.
   * .
   */
 -static void test_008_001_setup(void) {
 -  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +static void test_008_001_execute(void) {
 +  event_listener_t el1, el2;
 +
 +  /* [8.1.1] An Event Source is initialized.*/
 +  test_set_step(1);
 +  {
 +    chEvtObjectInit(&es1);
 +  }
 +
 +  /* [8.1.2] Two Event Listeners are registered on the Event Source,
 +     the Event Source is tested to have listeners.*/
 +  test_set_step(2);
 +  {
 +    chEvtRegisterMask(&es1, &el1, 1);
 +    chEvtRegisterMask(&es1, &el2, 2);
 +    test_assert_lock(chEvtIsListeningI(&es1), "no listener");
 +  }
 +
 +  /* [8.1.3] An Event Listener is unregistered, the Event Source must
 +     still have listeners.*/
 +  test_set_step(3);
 +  {
 +    chEvtUnregister(&es1, &el1);
 +    test_assert_lock(chEvtIsListeningI(&es1), "no listener");
 +  }
 +
 +  /* [8.1.4] An Event Listener is unregistered, the Event Source must
 +     not have listeners.*/
 +  test_set_step(4);
 +  {
 +    chEvtUnregister(&es1, &el2);
 +    test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
 +  }
  }
 -static void test_008_001_teardown(void) {
 -  chMBReset(&mb1);
 +static const testcase_t test_008_001 = {
 +  "Events registration",
 +  NULL,
 +  NULL,
 +  test_008_001_execute
 +};
 +
 +/**
 + * @page test_008_002 [8.2] Event Flags dispatching
 + *
 + * <h2>Description</h2>
 + * The test dispatches three event flags and verifies that the
 + * associated event handlers are invoked in LSb-first order.
 + *
 + * <h2>Test Steps</h2>
 + * - [8.2.1] Three evenf flag bits are raised then chEvtDispatch() is
 + *   invoked, the sequence of handlers calls is tested.
 + * .
 + */
 +
 +static void test_008_002_setup(void) {
 +  chEvtGetAndClearEvents(ALL_EVENTS);
  }
 -static void test_008_001_execute(void) {
 -  msg_t msg1, msg2;
 -  unsigned i;
 +static void test_008_002_execute(void) {
 -  /* [8.1.1] Testing the mailbox size.*/
 +  /* [8.2.1] Three evenf flag bits are raised then chEvtDispatch() is
 +     invoked, the sequence of handlers calls is tested.*/
    test_set_step(1);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
 +    chEvtDispatch(evhndl, 7);
 +    test_assert_sequence("ABC", "invalid sequence");
    }
 +}
 +
 +static const testcase_t test_008_002 = {
 +  "Event Flags dispatching",
 +  test_008_002_setup,
 +  NULL,
 +  test_008_002_execute
 +};
 +
 +/**
 + * @page test_008_003 [8.3] Events Flags wait using chEvtWaitOne()
 + *
 + * <h2>Description</h2>
 + * Functionality of chEvtWaitOne() is tested under various scenarios.
 + *
 + * <h2>Test Steps</h2>
 + * - [8.3.1] Setting three event flags.
 + * - [8.3.2] Calling chEvtWaitOne() three times, each time a single
 + *   flag must be returned in order of priority.
 + * - [8.3.3] Getting current time and starting a signaler thread, the
 + *   thread will set an event flag after 50mS.
 + * - [8.3.4] Calling chEvtWaitOne() then verifying that the event has
 + *   been received after 50mS and that the event flags mask has been
 + *   emptied.
 + * .
 + */
 -  /* [8.1.2] Resetting the mailbox, conditions are checked, no errors
 -     expected.*/
 +static void test_008_003_setup(void) {
 +  chEvtGetAndClearEvents(ALL_EVENTS);
 +}
 +
 +static void test_008_003_execute(void) {
 +  eventmask_t m;
 +  systime_t target_time;
 +
 +  /* [8.3.1] Setting three event flags.*/
 +  test_set_step(1);
 +  {
 +    chEvtAddEvents(7);
 +  }
 +
 +  /* [8.3.2] Calling chEvtWaitOne() three times, each time a single
 +     flag must be returned in order of priority.*/
    test_set_step(2);
    {
 -    chMBReset(&mb1);
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    m = chEvtWaitOne(ALL_EVENTS);
 +    test_assert(m == 1, "single event error");
 +    m = chEvtWaitOne(ALL_EVENTS);
 +    test_assert(m == 2, "single event error");
 +    m = chEvtWaitOne(ALL_EVENTS);
 +    test_assert(m == 4, "single event error");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
    }
 -  /* [8.1.3] Testing the behavior of API when the mailbox is in reset
 -     state then return in active state.*/
 +  /* [8.3.3] Getting current time and starting a signaler thread, the
 +     thread will set an event flag after 50mS.*/
    test_set_step(3);
    {
 -    msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
 -    test_assert(msg1 == MSG_RESET, "not in reset state");
 -    msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
 -    test_assert(msg1 == MSG_RESET, "not in reset state");
 -    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -    test_assert(msg1 == MSG_RESET, "not in reset state");
 -    chMBResumeX(&mb1);
 +    target_time = test_wait_tick() + MS2ST(50);
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 +                                   evt_thread3, chThdGetSelfX());
    }
 -  /* [8.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 -     once, no errors expected.*/
 +  /* [8.3.4] Calling chEvtWaitOne() then verifying that the event has
 +     been received after 50mS and that the event flags mask has been
 +     emptied.*/
    test_set_step(4);
    {
 -    for (i = 0; i < MB_SIZE - 1; i++) {
 -      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    }
 -    msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    m = chEvtWaitOne(ALL_EVENTS);
 +    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 +                            "out of time window");
 +    test_assert(m == 1, "event flag error");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
 +    test_wait_threads();
    }
 +}
 -  /* [8.1.5] Testing intermediate conditions. Data pointers must be
 -     aligned, semaphore counters are checked.*/
 -  test_set_step(5);
 +static const testcase_t test_008_003 = {
 +  "Events Flags wait using chEvtWaitOne()",
 +  test_008_003_setup,
 +  NULL,
 +  test_008_003_execute
 +};
 +
 +/**
 + * @page test_008_004 [8.4] Events Flags wait using chEvtWaitAny()
 + *
 + * <h2>Description</h2>
 + * Functionality of chEvtWaitAny() is tested under various scenarios.
 + *
 + * <h2>Test Steps</h2>
 + * - [8.4.1] Setting two, non contiguous, event flags.
 + * - [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
 + *   returned.
 + * - [8.4.3] Getting current time and starting a signaler thread, the
 + *   thread will set an event flag after 50mS.
 + * - [8.4.4] Calling chEvtWaitAny() then verifying that the event has
 + *   been received after 50mS and that the event flags mask has been
 + *   emptied.
 + * .
 + */
 +
 +static void test_008_004_setup(void) {
 +  chEvtGetAndClearEvents(ALL_EVENTS);
 +}
 +
 +static void test_008_004_execute(void) {
 +  eventmask_t m;
 +  systime_t target_time;
 +
 +  /* [8.4.1] Setting two, non contiguous, event flags.*/
 +  test_set_step(1);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 -    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
 +    chEvtAddEvents(5);
    }
 -  /* [8.1.6] Emptying the mailbox using chMBFetch(), no errors
 -     expected.*/
 -  test_set_step(6);
 +  /* [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
 +     returned.*/
 +  test_set_step(2);
    {
 -    for (i = 0; i < MB_SIZE; i++) {
 -      msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -      test_emit_token(msg2);
 -    }
 -    test_assert_sequence("ABCD", "wrong get sequence");
 +    m = chEvtWaitAny(ALL_EVENTS);
 +    test_assert(m == 5, "unexpected pending bit");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
    }
 -  /* [8.1.7] Posting and then fetching one more message, no errors
 -     expected.*/
 -  test_set_step(7);
 +  /* [8.4.3] Getting current time and starting a signaler thread, the
 +     thread will set an event flag after 50mS.*/
 +  test_set_step(3);
    {
 -    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    target_time = test_wait_tick() + MS2ST(50);
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 +                                   evt_thread3, chThdGetSelfX());
    }
 -  /* [8.1.8] Testing final conditions. Data pointers must be aligned to
 -     buffer start, semaphore counters are checked.*/
 -  test_set_step(8);
 +  /* [8.4.4] Calling chEvtWaitAny() then verifying that the event has
 +     been received after 50mS and that the event flags mask has been
 +     emptied.*/
 +  test_set_step(4);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    m = chEvtWaitAny(ALL_EVENTS);
 +    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 +                            "out of time window");
 +    test_assert(m == 1, "event flag error");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
 +    test_wait_threads();
    }
  }
 -static const testcase_t test_008_001 = {
 -  "Mailbox normal API, non-blocking tests",
 -  test_008_001_setup,
 -  test_008_001_teardown,
 -  test_008_001_execute
 +static const testcase_t test_008_004 = {
 +  "Events Flags wait using chEvtWaitAny()",
 +  test_008_004_setup,
 +  NULL,
 +  test_008_004_execute
  };
  /**
 - * @page test_008_002 [8.2] Mailbox I-Class API, non-blocking tests
 + * @page test_008_005 [8.5] Events Flags wait using chEvtWaitAll()
   *
   * <h2>Description</h2>
 - * The mailbox I-Class API is tested without triggering blocking
 - * conditions.
 + * Functionality of chEvtWaitAll() is tested under various scenarios.
   *
   * <h2>Test Steps</h2>
 - * - [8.2.1] Testing the mailbox size.
 - * - [8.2.2] Resetting the mailbox, conditions are checked, no errors
 - *   expected. The mailbox is then returned in active state.
 - * - [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 - *   once, no errors expected.
 - * - [8.2.4] Testing intermediate conditions. Data pointers must be
 - *   aligned, semaphore counters are checked.
 - * - [8.2.5] Emptying the mailbox using chMBFetchI(), no errors
 - *   expected.
 - * - [8.2.6] Posting and then fetching one more message, no errors
 - *   expected.
 - * - [8.2.7] Testing final conditions. Data pointers must be aligned to
 - *   buffer start, semaphore counters are checked.
 + * - [8.5.1] Setting two, non contiguous, event flags.
 + * - [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
 + *   returned.
 + * - [8.5.3] Setting one event flag.
 + * - [8.5.4] Getting current time and starting a signaler thread, the
 + *   thread will set another event flag after 50mS.
 + * - [8.5.5] Calling chEvtWaitAll() then verifying that both event
 + *   flags have been received after 50mS and that the event flags mask
 + *   has been emptied.
   * .
   */
 -static void test_008_002_setup(void) {
 -  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +static void test_008_005_setup(void) {
 +  chEvtGetAndClearEvents(ALL_EVENTS);
  }
 -static void test_008_002_teardown(void) {
 -  chMBReset(&mb1);
 -}
 +static void test_008_005_execute(void) {
 +  eventmask_t m;
 +  systime_t target_time;
 -static void test_008_002_execute(void) {
 -  msg_t msg1, msg2;
 -  unsigned i;
 -
 -  /* [8.2.1] Testing the mailbox size.*/
 +  /* [8.5.1] Setting two, non contiguous, event flags.*/
    test_set_step(1);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
 +    chEvtAddEvents(5);
    }
 -  /* [8.2.2] Resetting the mailbox, conditions are checked, no errors
 -     expected. The mailbox is then returned in active state.*/
 +  /* [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
 +     returned.*/
    test_set_step(2);
    {
 -    chSysLock();
 -    chMBResetI(&mb1);
 -    chSysUnlock();
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 -    chMBResumeX(&mb1);
 +    m = chEvtWaitAll(5);
 +    test_assert(m == 5, "unexpected pending bit");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
    }
 -  /* [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 -     once, no errors expected.*/
 +  /* [8.5.3] Setting one event flag.*/
    test_set_step(3);
    {
 -    for (i = 0; i < MB_SIZE - 1; i++) {
 -      chSysLock();
 -      msg1 = chMBPostI(&mb1, 'B' + i);
 -      chSysUnlock();
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    }
 -    chSysLock();
 -    msg1 = chMBPostAheadI(&mb1, 'A');
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    chEvtAddEvents(4);
    }
 -  /* [8.2.4] Testing intermediate conditions. Data pointers must be
 -     aligned, semaphore counters are checked.*/
 +  /* [8.5.4] Getting current time and starting a signaler thread, the
 +     thread will set another event flag after 50mS.*/
    test_set_step(4);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 -    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
 +    target_time = test_wait_tick() + MS2ST(50);
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 +                                   evt_thread3, chThdGetSelfX());
    }
 -  /* [8.2.5] Emptying the mailbox using chMBFetchI(), no errors
 -     expected.*/
 +  /* [8.5.5] Calling chEvtWaitAll() then verifying that both event
 +     flags have been received after 50mS and that the event flags mask
 +     has been emptied.*/
    test_set_step(5);
    {
 -    for (i = 0; i < MB_SIZE; i++) {
 -      chSysLock();
 -      msg1 = chMBFetchI(&mb1, &msg2);
 -      chSysUnlock();
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -      test_emit_token(msg2);
 -    }
 -    test_assert_sequence("ABCD", "wrong get sequence");
 +    m = chEvtWaitAll(5);
 +    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 +                            "out of time window");
 +    test_assert(m == 5, "event flags error");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
 +    test_wait_threads();
    }
 +}
 -  /* [8.2.6] Posting and then fetching one more message, no errors
 -     expected.*/
 -  test_set_step(6);
 +static const testcase_t test_008_005 = {
 +  "Events Flags wait using chEvtWaitAll()",
 +  test_008_005_setup,
 +  NULL,
 +  test_008_005_execute
 +};
 +
 +#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
 +/**
 + * @page test_008_006 [8.6] Events Flags wait timeouts
 + *
 + * <h2>Description</h2>
 + * Timeout functionality is tested for chEvtWaitOneTimeout(),
 + * chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_EVENTS_TIMEOUT
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [8.6.1] The functions are invoked first with TIME_IMMEDIATE
 + *   timeout, the timeout condition is tested.
 + * - [8.6.2] The functions are invoked first with a 50mS timeout, the
 + *   timeout condition is tested.
 + * .
 + */
 +
 +static void test_008_006_setup(void) {
 +  chEvtGetAndClearEvents(ALL_EVENTS);
 +}
 +
 +static void test_008_006_execute(void) {
 +  eventmask_t m;
 +
 +  /* [8.6.1] The functions are invoked first with TIME_IMMEDIATE
 +     timeout, the timeout condition is tested.*/
 +  test_set_step(1);
    {
 -    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 -    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
 +    test_assert(m == 0, "spurious event");
 +    m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
 +    test_assert(m == 0, "spurious event");
 +    m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
 +    test_assert(m == 0, "spurious event");
    }
 -  /* [8.2.7] Testing final conditions. Data pointers must be aligned to
 -     buffer start, semaphore counters are checked.*/
 -  test_set_step(7);
 +  /* [8.6.2] The functions are invoked first with a 50mS timeout, the
 +     timeout condition is tested.*/
 +  test_set_step(2);
    {
 -    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 -    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 -    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 -    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    m = chEvtWaitOneTimeout(ALL_EVENTS, MS2ST(50));
 +    test_assert(m == 0, "spurious event");
 +    m = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(50));
 +    test_assert(m == 0, "spurious event");
 +    m = chEvtWaitAllTimeout(ALL_EVENTS, MS2ST(50));
 +    test_assert(m == 0, "spurious event");
    }
  }
 -static const testcase_t test_008_002 = {
 -  "Mailbox I-Class API, non-blocking tests",
 -  test_008_002_setup,
 -  test_008_002_teardown,
 -  test_008_002_execute
 +static const testcase_t test_008_006 = {
 +  "Events Flags wait timeouts",
 +  test_008_006_setup,
 +  NULL,
 +  test_008_006_execute
  };
 +#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
  /**
 - * @page test_008_003 [8.3] Mailbox timeouts
 + * @page test_008_007 [8.7] Broadcasting using chEvtBroadcast()
   *
   * <h2>Description</h2>
 - * The mailbox API is tested for timeouts.
 + * Functionality of chEvtBroadcast() is tested.
   *
   * <h2>Test Steps</h2>
 - * - [8.3.1] Filling the mailbox.
 - * - [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 - *   chMBPostAheadI() timeout.
 - * - [8.3.3] Resetting the mailbox. The mailbox is then returned in
 - *   active state.
 - * - [8.3.4] Testing chMBFetch() and chMBFetchI() timeout.
 + * - [8.7.1] Registering on two event sources associating them with
 + *   flags 1 and 4.
 + * - [8.7.2] Getting current time and starting a broadcaster thread,
 + *   the thread broadcast the first Event Source immediately and the
 + *   other after 50mS.
 + * - [8.7.3] Calling chEvtWaitAll() then verifying that both event
 + *   flags have been received after 50mS and that the event flags mask
 + *   has been emptied.
 + * - [8.7.4] Unregistering from the Event Sources.
   * .
   */
 -static void test_008_003_setup(void) {
 -  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 -}
 -
 -static void test_008_003_teardown(void) {
 -  chMBReset(&mb1);
 +static void test_008_007_setup(void) {
 +  chEvtGetAndClearEvents(ALL_EVENTS);
 +  chEvtObjectInit(&es1);
 +  chEvtObjectInit(&es2);
  }
 -static void test_008_003_execute(void) {
 -  msg_t msg1, msg2;
 -  unsigned i;
 +static void test_008_007_execute(void) {
 +  eventmask_t m;
 +  event_listener_t el1, el2;
 +  systime_t target_time;
 -  /* [8.3.1] Filling the mailbox.*/
 +  /* [8.7.1] Registering on two event sources associating them with
 +     flags 1 and 4.*/
    test_set_step(1);
    {
 -    for (i = 0; i < MB_SIZE; i++) {
 -      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 -      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 -    }
 +    chEvtRegisterMask(&es1, &el1, 1);
 +    chEvtRegisterMask(&es2, &el2, 4);
    }
 -  /* [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 -     chMBPostAheadI() timeout.*/
 +  /* [8.7.2] Getting current time and starting a broadcaster thread,
 +     the thread broadcast the first Event Source immediately and the
 +     other after 50mS.*/
    test_set_step(2);
    {
 -    msg1 = chMBPost(&mb1, 'X', 1);
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    chSysLock();
 -    msg1 = chMBPostI(&mb1, 'X');
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    msg1 = chMBPostAhead(&mb1, 'X', 1);
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    chSysLock();
 -    msg1 = chMBPostAheadI(&mb1, 'X');
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    target_time = test_wait_tick() + MS2ST(50);
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
 +                                   evt_thread7, "A");
    }
 -  /* [8.3.3] Resetting the mailbox. The mailbox is then returned in
 -     active state.*/
 +  /* [8.7.3] Calling chEvtWaitAll() then verifying that both event
 +     flags have been received after 50mS and that the event flags mask
 +     has been emptied.*/
    test_set_step(3);
    {
 -    chMBReset(&mb1);
 -    chMBResumeX(&mb1);
 +    m = chEvtWaitAll(5);
 +    test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
 +                            "out of time window");
 +    m = chEvtGetAndClearEvents(ALL_EVENTS);
 +    test_assert(m == 0, "stuck event");
 +    test_wait_threads();
    }
 -  /* [8.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
 +  /* [8.7.4] Unregistering from the Event Sources.*/
    test_set_step(4);
    {
 -    msg1 = chMBFetch(&mb1, &msg2, 1);
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 -    chSysLock();
 -    msg1 = chMBFetchI(&mb1, &msg2);
 -    chSysUnlock();
 -    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chEvtUnregister(&es1, &el1);
 +    chEvtUnregister(&es2, &el2);
 +    test_assert(!chEvtIsListeningI(&es1), "stuck listener");
 +    test_assert(!chEvtIsListeningI(&es2), "stuck listener");
    }
  }
 -static const testcase_t test_008_003 = {
 -  "Mailbox timeouts",
 -  test_008_003_setup,
 -  test_008_003_teardown,
 -  test_008_003_execute
 +static const testcase_t test_008_007 = {
 +  "Broadcasting using chEvtBroadcast()",
 +  test_008_007_setup,
 +  NULL,
 +  test_008_007_execute
  };
  /****************************************************************************
 @@ -397,13 +551,19 @@ static const testcase_t test_008_003 = {   ****************************************************************************/
  /**
 - * @brief   Mailboxes.
 + * @brief   Event Sources and Event Flags.
   */
  const testcase_t * const test_sequence_008[] = {
    &test_008_001,
    &test_008_002,
    &test_008_003,
 +  &test_008_004,
 +  &test_008_005,
 +#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
 +  &test_008_006,
 +#endif
 +  &test_008_007,
    NULL
  };
 -#endif /* CH_CFG_USE_MAILBOXES */
 +#endif /* CH_CFG_USE_EVENTS */
 diff --git a/test/rt/source/test/test_sequence_009.c b/test/rt/source/test/test_sequence_009.c index 6f4650b8a..e722da0c4 100644 --- a/test/rt/source/test/test_sequence_009.c +++ b/test/rt/source/test/test_sequence_009.c @@ -22,18 +22,18 @@   * @file    test_sequence_009.c
   * @brief   Test Sequence 009 code.
   *
 - * @page test_sequence_009 [9] Memory Pools
 + * @page test_sequence_009 [9] Mailboxes
   *
   * File: @ref test_sequence_009.c
   *
   * <h2>Description</h2>
 - * This sequence tests the ChibiOS/RT functionalities related to memory
 - * pools.
 + * This sequence tests the ChibiOS/RT functionalities related to
 + * mailboxes.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MEMPOOLS
 + * - CH_CFG_USE_MAILBOXES
   * .
   *
   * <h2>Test Cases</h2>
 @@ -43,254 +43,367 @@   * .
   */
 -#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#define MEMORY_POOL_SIZE 4
 +#define MB_SIZE 4
 -static uint32_t objects[MEMORY_POOL_SIZE];
 -static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
 -
 -#if CH_CFG_USE_SEMAPHORES
 -static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
 -#endif
 -
 -static void *null_provider(size_t size, unsigned align) {
 -
 -  (void)size;
 -  (void)align;
 -
 -  return NULL;
 -}
 +static msg_t mb_buffer[MB_SIZE];
 +static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_009_001 [9.1] Loading and emptying a memory pool
 + * @page test_009_001 [9.1] Mailbox normal API, non-blocking tests
   *
   * <h2>Description</h2>
 - * The memory pool functionality is tested by loading and emptying it,
 - * all conditions are tested.
 + * The mailbox normal API is tested without triggering blocking
 + * conditions.
   *
   * <h2>Test Steps</h2>
 - * - [9.1.1] Adding the objects to the pool using chPoolLoadArray().
 - * - [9.1.2] Emptying the pool using chPoolAlloc().
 - * - [9.1.3] Now must be empty.
 - * - [9.1.4] Adding the objects to the pool using chPoolFree().
 - * - [9.1.5] Emptying the pool using chPoolAlloc() again.
 - * - [9.1.6] Now must be empty again.
 - * - [9.1.7] Covering the case where a provider is unable to return
 - *   more memory.
 + * - [9.1.1] Testing the mailbox size.
 + * - [9.1.2] Resetting the mailbox, conditions are checked, no errors
 + *   expected.
 + * - [9.1.3] Testing the behavior of API when the mailbox is in reset
 + *   state then return in active state.
 + * - [9.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 + *   once, no errors expected.
 + * - [9.1.5] Testing intermediate conditions. Data pointers must be
 + *   aligned, semaphore counters are checked.
 + * - [9.1.6] Emptying the mailbox using chMBFetch(), no errors
 + *   expected.
 + * - [9.1.7] Posting and then fetching one more message, no errors
 + *   expected.
 + * - [9.1.8] Testing final conditions. Data pointers must be aligned to
 + *   buffer start, semaphore counters are checked.
   * .
   */
  static void test_009_001_setup(void) {
 -  chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
 +  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +}
 +
 +static void test_009_001_teardown(void) {
 +  chMBReset(&mb1);
  }
  static void test_009_001_execute(void) {
 +  msg_t msg1, msg2;
    unsigned i;
 -  /* [9.1.1] Adding the objects to the pool using chPoolLoadArray().*/
 +  /* [9.1.1] Testing the mailbox size.*/
    test_set_step(1);
    {
 -    chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
    }
 -  /* [9.1.2] Emptying the pool using chPoolAlloc().*/
 +  /* [9.1.2] Resetting the mailbox, conditions are checked, no errors
 +     expected.*/
    test_set_step(2);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
 +    chMBReset(&mb1);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
    }
 -  /* [9.1.3] Now must be empty.*/
 +  /* [9.1.3] Testing the behavior of API when the mailbox is in reset
 +     state then return in active state.*/
    test_set_step(3);
    {
 -    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
 +    msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
 +    test_assert(msg1 == MSG_RESET, "not in reset state");
 +    msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
 +    test_assert(msg1 == MSG_RESET, "not in reset state");
 +    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +    test_assert(msg1 == MSG_RESET, "not in reset state");
 +    chMBResumeX(&mb1);
    }
 -  /* [9.1.4] Adding the objects to the pool using chPoolFree().*/
 +  /* [9.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
 +     once, no errors expected.*/
    test_set_step(4);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      chPoolFree(&mp1, &objects[i]);
 +    for (i = 0; i < MB_SIZE - 1; i++) {
 +      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    }
 +    msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
    }
 -  /* [9.1.5] Emptying the pool using chPoolAlloc() again.*/
 +  /* [9.1.5] Testing intermediate conditions. Data pointers must be
 +     aligned, semaphore counters are checked.*/
    test_set_step(5);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 +    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
    }
 -  /* [9.1.6] Now must be empty again.*/
 +  /* [9.1.6] Emptying the mailbox using chMBFetch(), no errors
 +     expected.*/
    test_set_step(6);
    {
 -    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
 +    for (i = 0; i < MB_SIZE; i++) {
 +      msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +      test_emit_token(msg2);
 +    }
 +    test_assert_sequence("ABCD", "wrong get sequence");
    }
 -  /* [9.1.7] Covering the case where a provider is unable to return
 -     more memory.*/
 +  /* [9.1.7] Posting and then fetching one more message, no errors
 +     expected.*/
    test_set_step(7);
    {
 -    chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
 -    test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
 +    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +  }
 +
 +  /* [9.1.8] Testing final conditions. Data pointers must be aligned to
 +     buffer start, semaphore counters are checked.*/
 +  test_set_step(8);
 +  {
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
    }
  }
  static const testcase_t test_009_001 = {
 -  "Loading and emptying a memory pool",
 +  "Mailbox normal API, non-blocking tests",
    test_009_001_setup,
 -  NULL,
 +  test_009_001_teardown,
    test_009_001_execute
  };
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /**
 - * @page test_009_002 [9.2] Loading and emptying a guarded memory pool without waiting
 + * @page test_009_002 [9.2] Mailbox I-Class API, non-blocking tests
   *
   * <h2>Description</h2>
 - * The memory pool functionality is tested by loading and emptying it,
 - * all conditions are tested.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 + * The mailbox I-Class API is tested without triggering blocking
 + * conditions.
   *
   * <h2>Test Steps</h2>
 - * - [9.2.1] Adding the objects to the pool using
 - *   chGuardedPoolLoadArray().
 - * - [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
 - * - [9.2.3] Now must be empty.
 - * - [9.2.4] Adding the objects to the pool using chGuardedPoolFree().
 - * - [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
 - * - [9.2.6] Now must be empty again.
 + * - [9.2.1] Testing the mailbox size.
 + * - [9.2.2] Resetting the mailbox, conditions are checked, no errors
 + *   expected. The mailbox is then returned in active state.
 + * - [9.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 + *   once, no errors expected.
 + * - [9.2.4] Testing intermediate conditions. Data pointers must be
 + *   aligned, semaphore counters are checked.
 + * - [9.2.5] Emptying the mailbox using chMBFetchI(), no errors
 + *   expected.
 + * - [9.2.6] Posting and then fetching one more message, no errors
 + *   expected.
 + * - [9.2.7] Testing final conditions. Data pointers must be aligned to
 + *   buffer start, semaphore counters are checked.
   * .
   */
  static void test_009_002_setup(void) {
 -  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +}
 +
 +static void test_009_002_teardown(void) {
 +  chMBReset(&mb1);
  }
  static void test_009_002_execute(void) {
 +  msg_t msg1, msg2;
    unsigned i;
 -  /* [9.2.1] Adding the objects to the pool using
 -     chGuardedPoolLoadArray().*/
 +  /* [9.2.1] Testing the mailbox size.*/
    test_set_step(1);
    {
 -    chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
    }
 -  /* [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
 +  /* [9.2.2] Resetting the mailbox, conditions are checked, no errors
 +     expected. The mailbox is then returned in active state.*/
    test_set_step(2);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +    chSysLock();
 +    chMBResetI(&mb1);
 +    chSysUnlock();
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
 +    chMBResumeX(&mb1);
    }
 -  /* [9.2.3] Now must be empty.*/
 +  /* [9.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
 +     once, no errors expected.*/
    test_set_step(3);
    {
 -    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
 +    for (i = 0; i < MB_SIZE - 1; i++) {
 +      chSysLock();
 +      msg1 = chMBPostI(&mb1, 'B' + i);
 +      chSysUnlock();
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    }
 +    chSysLock();
 +    msg1 = chMBPostAheadI(&mb1, 'A');
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
    }
 -  /* [9.2.4] Adding the objects to the pool using
 -     chGuardedPoolFree().*/
 +  /* [9.2.4] Testing intermediate conditions. Data pointers must be
 +     aligned, semaphore counters are checked.*/
    test_set_step(4);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      chGuardedPoolFree(&gmp1, &objects[i]);
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
 +    test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
    }
 -  /* [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
 -     again.*/
 +  /* [9.2.5] Emptying the mailbox using chMBFetchI(), no errors
 +     expected.*/
    test_set_step(5);
    {
 -    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 -      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +    for (i = 0; i < MB_SIZE; i++) {
 +      chSysLock();
 +      msg1 = chMBFetchI(&mb1, &msg2);
 +      chSysUnlock();
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +      test_emit_token(msg2);
 +    }
 +    test_assert_sequence("ABCD", "wrong get sequence");
    }
 -  /* [9.2.6] Now must be empty again.*/
 +  /* [9.2.6] Posting and then fetching one more message, no errors
 +     expected.*/
    test_set_step(6);
    {
 -    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
 +    msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
 +    test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +  }
 +
 +  /* [9.2.7] Testing final conditions. Data pointers must be aligned to
 +     buffer start, semaphore counters are checked.*/
 +  test_set_step(7);
 +  {
 +    test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
 +    test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
 +    test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
 +    test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
    }
  }
  static const testcase_t test_009_002 = {
 -  "Loading and emptying a guarded memory pool without waiting",
 +  "Mailbox I-Class API, non-blocking tests",
    test_009_002_setup,
 -  NULL,
 +  test_009_002_teardown,
    test_009_002_execute
  };
 -#endif /* CH_CFG_USE_SEMAPHORES */
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /**
 - * @page test_009_003 [9.3] Guarded Memory Pools timeout
 + * @page test_009_003 [9.3] Mailbox timeouts
   *
   * <h2>Description</h2>
 - * The timeout features for the Guarded Memory Pools is tested.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 + * The mailbox API is tested for timeouts.
   *
   * <h2>Test Steps</h2>
 - * - [9.3.1] Trying to allocate with 100mS timeout, must fail because
 - *   the pool is empty.
 + * - [9.3.1] Filling the mailbox.
 + * - [9.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 + *   chMBPostAheadI() timeout.
 + * - [9.3.3] Resetting the mailbox. The mailbox is then returned in
 + *   active state.
 + * - [9.3.4] Testing chMBFetch() and chMBFetchI() timeout.
   * .
   */
  static void test_009_003_setup(void) {
 -  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +  chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
 +}
 +
 +static void test_009_003_teardown(void) {
 +  chMBReset(&mb1);
  }
  static void test_009_003_execute(void) {
 +  msg_t msg1, msg2;
 +  unsigned i;
 -  /* [9.3.1] Trying to allocate with 100mS timeout, must fail because
 -     the pool is empty.*/
 +  /* [9.3.1] Filling the mailbox.*/
    test_set_step(1);
    {
 -    test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
 +    for (i = 0; i < MB_SIZE; i++) {
 +      msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
 +      test_assert(msg1 == MSG_OK, "wrong wake-up message");
 +    }
 +  }
 +
 +  /* [9.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
 +     chMBPostAheadI() timeout.*/
 +  test_set_step(2);
 +  {
 +    msg1 = chMBPost(&mb1, 'X', 1);
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chSysLock();
 +    msg1 = chMBPostI(&mb1, 'X');
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    msg1 = chMBPostAhead(&mb1, 'X', 1);
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chSysLock();
 +    msg1 = chMBPostAheadI(&mb1, 'X');
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +  }
 +
 +  /* [9.3.3] Resetting the mailbox. The mailbox is then returned in
 +     active state.*/
 +  test_set_step(3);
 +  {
 +    chMBReset(&mb1);
 +    chMBResumeX(&mb1);
 +  }
 +
 +  /* [9.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
 +  test_set_step(4);
 +  {
 +    msg1 = chMBFetch(&mb1, &msg2, 1);
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
 +    chSysLock();
 +    msg1 = chMBFetchI(&mb1, &msg2);
 +    chSysUnlock();
 +    test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
    }
  }
  static const testcase_t test_009_003 = {
 -  "Guarded Memory Pools timeout",
 +  "Mailbox timeouts",
    test_009_003_setup,
 -  NULL,
 +  test_009_003_teardown,
    test_009_003_execute
  };
 -#endif /* CH_CFG_USE_SEMAPHORES */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Memory Pools.
 + * @brief   Mailboxes.
   */
  const testcase_t * const test_sequence_009[] = {
    &test_009_001,
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    &test_009_002,
 -#endif
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    &test_009_003,
 -#endif
    NULL
  };
 -#endif /* CH_CFG_USE_MEMPOOLS */
 +#endif /* CH_CFG_USE_MAILBOXES */
 diff --git a/test/rt/source/test/test_sequence_010.c b/test/rt/source/test/test_sequence_010.c index 480021eb6..72828ad86 100644 --- a/test/rt/source/test/test_sequence_010.c +++ b/test/rt/source/test/test_sequence_010.c @@ -22,251 +22,276 @@   * @file    test_sequence_010.c
   * @brief   Test Sequence 010 code.
   *
 - * @page test_sequence_010 [10] Memory Heaps
 + * @page test_sequence_010 [10] Memory Pools
   *
   * File: @ref test_sequence_010.c
   *
   * <h2>Description</h2>
   * This sequence tests the ChibiOS/RT functionalities related to memory
 - * heaps.
 + * pools.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_HEAP
 + * - CH_CFG_USE_MEMPOOLS
   * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_010_001
   * - @subpage test_010_002
 + * - @subpage test_010_003
   * .
   */
 -#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#define ALLOC_SIZE 16
 -#define HEAP_SIZE (ALLOC_SIZE * 8)
 +#define MEMORY_POOL_SIZE 4
 -memory_heap_t test_heap;
 +static uint32_t objects[MEMORY_POOL_SIZE];
 +static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
 +
 +#if CH_CFG_USE_SEMAPHORES
 +static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
 +#endif
 +
 +static void *null_provider(size_t size, unsigned align) {
 +
 +  (void)size;
 +  (void)align;
 +
 +  return NULL;
 +}
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
  /**
 - * @page test_010_001 [10.1] Allocation and fragmentation
 + * @page test_010_001 [10.1] Loading and emptying a memory pool
   *
   * <h2>Description</h2>
 - * Series of allocations/deallocations are performed in carefully
 - * designed sequences in order to stimulate all the possible code paths
 - * inside the allocator. The test expects to find the heap back to the
 - * initial status after each sequence.
 + * The memory pool functionality is tested by loading and emptying it,
 + * all conditions are tested.
   *
   * <h2>Test Steps</h2>
 - * - [10.1.1] Testing initial conditions, the heap must not be
 - *   fragmented and one free block present.
 - * - [10.1.2] Trying to allocate an block bigger than available space,
 - *   an error is expected.
 - * - [10.1.3] Single block allocation using chHeapAlloc() then the
 - *   block is freed using chHeapFree(), must not fail.
 - * - [10.1.4] Using chHeapStatus() to assess the heap state. There must
 - *   be at least one free block of sufficient size.
 - * - [10.1.5] Allocating then freeing in the same order.
 - * - [10.1.6] Allocating then freeing in reverse order.
 - * - [10.1.7] Small fragments handling. Checking the behavior when
 - *   allocating blocks with size not multiple of alignment unit.
 - * - [10.1.8] Skipping a fragment, the first fragment in the list is
 - *   too small so the allocator must pick the second one.
 - * - [10.1.9] Allocating the whole available space.
 - * - [10.1.10] Testing final conditions. The heap geometry must be the
 - *   same than the one registered at beginning.
 + * - [10.1.1] Adding the objects to the pool using chPoolLoadArray().
 + * - [10.1.2] Emptying the pool using chPoolAlloc().
 + * - [10.1.3] Now must be empty.
 + * - [10.1.4] Adding the objects to the pool using chPoolFree().
 + * - [10.1.5] Emptying the pool using chPoolAlloc() again.
 + * - [10.1.6] Now must be empty again.
 + * - [10.1.7] Covering the case where a provider is unable to return
 + *   more memory.
   * .
   */
  static void test_010_001_setup(void) {
 -  chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer));
 +  chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
  }
  static void test_010_001_execute(void) {
 -  void *p1, *p2, *p3;
 -  size_t n, sz;
 +  unsigned i;
 -  /* [10.1.1] Testing initial conditions, the heap must not be
 -     fragmented and one free block present.*/
 +  /* [10.1.1] Adding the objects to the pool using chPoolLoadArray().*/
    test_set_step(1);
    {
 -    test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
 +    chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
    }
 -  /* [10.1.2] Trying to allocate an block bigger than available space,
 -     an error is expected.*/
 +  /* [10.1.2] Emptying the pool using chPoolAlloc().*/
    test_set_step(2);
    {
 -    p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2);
 -    test_assert(p1 == NULL, "allocation not failed");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
    }
 -  /* [10.1.3] Single block allocation using chHeapAlloc() then the
 -     block is freed using chHeapFree(), must not fail.*/
 +  /* [10.1.3] Now must be empty.*/
    test_set_step(3);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    test_assert(p1 != NULL, "allocation failed");
 -    chHeapFree(p1);
 +    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
    }
 -  /* [10.1.4] Using chHeapStatus() to assess the heap state. There must
 -     be at least one free block of sufficient size.*/
 +  /* [10.1.4] Adding the objects to the pool using chPoolFree().*/
    test_set_step(4);
    {
 -    size_t total_size, largest_size;
 -
 -    n = chHeapStatus(&test_heap, &total_size, &largest_size);
 -    test_assert(n == 1, "missing free block");
 -    test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
 -    test_assert(total_size == largest_size, "unexpected heap state");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      chPoolFree(&mp1, &objects[i]);
    }
 -  /* [10.1.5] Allocating then freeing in the same order.*/
 +  /* [10.1.5] Emptying the pool using chPoolAlloc() again.*/
    test_set_step(5);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p1);                                 /* Does not merge.*/
 -    chHeapFree(p2);                                 /* Merges backward.*/
 -    chHeapFree(p3);                                 /* Merges both sides.*/
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
    }
 -  /* [10.1.6] Allocating then freeing in reverse order.*/
 +  /* [10.1.6] Now must be empty again.*/
    test_set_step(6);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p3);                                 /* Merges forward.*/
 -    chHeapFree(p2);                                 /* Merges forward.*/
 -    chHeapFree(p1);                                 /* Merges forward.*/
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +    test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
    }
 -  /* [10.1.7] Small fragments handling. Checking the behavior when
 -     allocating blocks with size not multiple of alignment unit.*/
 +  /* [10.1.7] Covering the case where a provider is unable to return
 +     more memory.*/
    test_set_step(7);
    {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p1);
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    /* Note, the first situation happens when the alignment size is smaller
 -       than the header size, the second in the other cases.*/
 -    test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
 -                (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
 -    chHeapFree(p2);
 -    chHeapFree(p1);
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 -  }
 -
 -  /* [10.1.8] Skipping a fragment, the first fragment in the list is
 -     too small so the allocator must pick the second one.*/
 -  test_set_step(8);
 -  {
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    chHeapFree(p1);
 -    test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
 -    chHeapFree(p1);
 -    chHeapFree(p2);
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 -  }
 -
 -  /* [10.1.9] Allocating the whole available space.*/
 -  test_set_step(9);
 -  {
 -    (void)chHeapStatus(&test_heap, &n, NULL);
 -    p1 = chHeapAlloc(&test_heap, n);
 -    test_assert(p1 != NULL, "allocation failed");
 -    test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
 -    chHeapFree(p1);
 -  }
 -
 -  /* [10.1.10] Testing final conditions. The heap geometry must be the
 -     same than the one registered at beginning.*/
 -  test_set_step(10);
 -  {
 -    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 -    test_assert(n == sz, "size changed");
 +    chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
 +    test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
    }
  }
  static const testcase_t test_010_001 = {
 -  "Allocation and fragmentation",
 +  "Loading and emptying a memory pool",
    test_010_001_setup,
    NULL,
    test_010_001_execute
  };
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
  /**
 - * @page test_010_002 [10.2] Default Heap
 + * @page test_010_002 [10.2] Loading and emptying a guarded memory pool without waiting
   *
   * <h2>Description</h2>
 - * The default heap is pre-allocated in the system. We test base
 - * functionality.
 + * The memory pool functionality is tested by loading and emptying it,
 + * all conditions are tested.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
   *
   * <h2>Test Steps</h2>
 - * - [10.2.1] Single block allocation using chHeapAlloc() then the
 - *   block is freed using chHeapFree(), must not fail.
 - * - [10.2.2] Testing allocation failure.
 + * - [10.2.1] Adding the objects to the pool using
 + *   chGuardedPoolLoadArray().
 + * - [10.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
 + * - [10.2.3] Now must be empty.
 + * - [10.2.4] Adding the objects to the pool using chGuardedPoolFree().
 + * - [10.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
 + *   again.
 + * - [10.2.6] Now must be empty again.
   * .
   */
 +static void test_010_002_setup(void) {
 +  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +}
 +
  static void test_010_002_execute(void) {
 -  void *p1;
 -  size_t total_size, largest_size;
 +  unsigned i;
 -  /* [10.2.1] Single block allocation using chHeapAlloc() then the
 -     block is freed using chHeapFree(), must not fail.*/
 +  /* [10.2.1] Adding the objects to the pool using
 +     chGuardedPoolLoadArray().*/
    test_set_step(1);
    {
 -    (void)chHeapStatus(NULL, &total_size, &largest_size);
 -    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 -    test_assert(p1 != NULL, "allocation failed");
 -    chHeapFree(p1);
 +    chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
    }
 -  /* [10.2.2] Testing allocation failure.*/
 +  /* [10.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
    test_set_step(2);
    {
 -    p1 = chHeapAlloc(NULL, (size_t)-256);
 -    test_assert(p1 == NULL, "allocation not failed");
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +  }
 +
 +  /* [10.2.3] Now must be empty.*/
 +  test_set_step(3);
 +  {
 +    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
 +  }
 +
 +  /* [10.2.4] Adding the objects to the pool using
 +     chGuardedPoolFree().*/
 +  test_set_step(4);
 +  {
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      chGuardedPoolFree(&gmp1, &objects[i]);
 +  }
 +
 +  /* [10.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
 +     again.*/
 +  test_set_step(5);
 +  {
 +    for (i = 0; i < MEMORY_POOL_SIZE; i++)
 +      test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
 +  }
 +
 +  /* [10.2.6] Now must be empty again.*/
 +  test_set_step(6);
 +  {
 +    test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
    }
  }
  static const testcase_t test_010_002 = {
 -  "Default Heap",
 -  NULL,
 +  "Loading and emptying a guarded memory pool without waiting",
 +  test_010_002_setup,
    NULL,
    test_010_002_execute
  };
 +#endif /* CH_CFG_USE_SEMAPHORES */
 +
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +/**
 + * @page test_010_003 [10.3] Guarded Memory Pools timeout
 + *
 + * <h2>Description</h2>
 + * The timeout features for the Guarded Memory Pools is tested.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [10.3.1] Trying to allocate with 100mS timeout, must fail because
 + *   the pool is empty.
 + * .
 + */
 +
 +static void test_010_003_setup(void) {
 +  chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
 +}
 +
 +static void test_010_003_execute(void) {
 +
 +  /* [10.3.1] Trying to allocate with 100mS timeout, must fail because
 +     the pool is empty.*/
 +  test_set_step(1);
 +  {
 +    test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
 +  }
 +}
 +
 +static const testcase_t test_010_003 = {
 +  "Guarded Memory Pools timeout",
 +  test_010_003_setup,
 +  NULL,
 +  test_010_003_execute
 +};
 +#endif /* CH_CFG_USE_SEMAPHORES */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Memory Heaps.
 + * @brief   Memory Pools.
   */
  const testcase_t * const test_sequence_010[] = {
    &test_010_001,
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
    &test_010_002,
 +#endif
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +  &test_010_003,
 +#endif
    NULL
  };
 -#endif /* CH_CFG_USE_HEAP */
 +#endif /* CH_CFG_USE_MEMPOOLS */
 diff --git a/test/rt/source/test/test_sequence_011.c b/test/rt/source/test/test_sequence_011.c index 14ac5c051..1e5b4ee5f 100644 --- a/test/rt/source/test/test_sequence_011.c +++ b/test/rt/source/test/test_sequence_011.c @@ -22,18 +22,18 @@   * @file    test_sequence_011.c
   * @brief   Test Sequence 011 code.
   *
 - * @page test_sequence_011 [11] Dynamic threads
 + * @page test_sequence_011 [11] Memory Heaps
   *
   * File: @ref test_sequence_011.c
   *
   * <h2>Description</h2>
 - * This module implements the test sequence for the dynamic thread
 - * creation APIs.
 + * This sequence tests the ChibiOS/RT functionalities related to memory
 + * heaps.
   *
   * <h2>Conditions</h2>
   * This sequence is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_DYNAMIC
 + * - CH_CFG_USE_HEAP
   * .
   *
   * <h2>Test Cases</h2>
 @@ -42,243 +42,231 @@   * .
   */
 -#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#if CH_CFG_USE_HEAP
 -static memory_heap_t heap1;
 -#endif
 -#if CH_CFG_USE_MEMPOOLS
 -static memory_pool_t mp1;
 -#endif
 -
 -static THD_FUNCTION(dyn_thread1, p) {
 +#define ALLOC_SIZE 16
 +#define HEAP_SIZE (ALLOC_SIZE * 8)
 -  test_emit_token(*(char *)p);
 -}
 +memory_heap_t test_heap;
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
 -#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
  /**
 - * @page test_011_001 [11.1] Threads creation from Memory Heap
 + * @page test_011_001 [11.1] Allocation and fragmentation
   *
   * <h2>Description</h2>
 - * Two threads are started by allocating the memory from the Memory
 - * Heap then a third thread is started with a huge stack
 - * requirement.<br> The test expects the first two threads to
 - * successfully start and the third one to fail.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_HEAP
 - * .
 + * Series of allocations/deallocations are performed in carefully
 + * designed sequences in order to stimulate all the possible code paths
 + * inside the allocator. The test expects to find the heap back to the
 + * initial status after each sequence.
   *
   * <h2>Test Steps</h2>
 - * - [11.1.1] Getting base priority for threads.
 - * - [11.1.2] Getting heap info before the test.
 - * - [11.1.3] Creating thread 1, it is expected to succeed.
 - * - [11.1.4] Creating thread 2, it is expected to succeed.
 - * - [11.1.5] Creating thread 3, it is expected to fail.
 - * - [11.1.6] Letting threads execute then checking the start order and
 - *   freeing memory.
 - * - [11.1.7] Getting heap info again for verification.
 + * - [11.1.1] Testing initial conditions, the heap must not be
 + *   fragmented and one free block present.
 + * - [11.1.2] Trying to allocate an block bigger than available space,
 + *   an error is expected.
 + * - [11.1.3] Single block allocation using chHeapAlloc() then the
 + *   block is freed using chHeapFree(), must not fail.
 + * - [11.1.4] Using chHeapStatus() to assess the heap state. There must
 + *   be at least one free block of sufficient size.
 + * - [11.1.5] Allocating then freeing in the same order.
 + * - [11.1.6] Allocating then freeing in reverse order.
 + * - [11.1.7] Small fragments handling. Checking the behavior when
 + *   allocating blocks with size not multiple of alignment unit.
 + * - [11.1.8] Skipping a fragment, the first fragment in the list is
 + *   too small so the allocator must pick the second one.
 + * - [11.1.9] Allocating the whole available space.
 + * - [11.1.10] Testing final conditions. The heap geometry must be the
 + *   same than the one registered at beginning.
   * .
   */
  static void test_011_001_setup(void) {
 -  chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
 +  chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer));
  }
  static void test_011_001_execute(void) {
 -  size_t n1, total1, largest1;
 -  size_t n2, total2, largest2;
 -  tprio_t prio;
 +  void *p1, *p2, *p3;
 +  size_t n, sz;
 -  /* [11.1.1] Getting base priority for threads.*/
 +  /* [11.1.1] Testing initial conditions, the heap must not be
 +     fragmented and one free block present.*/
    test_set_step(1);
    {
 -    prio = chThdGetPriorityX();
 +    test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
    }
 -  /* [11.1.2] Getting heap info before the test.*/
 +  /* [11.1.2] Trying to allocate an block bigger than available space,
 +     an error is expected.*/
    test_set_step(2);
    {
 -    n1 = chHeapStatus(&heap1, &total1, &largest1);
 -    test_assert(n1 == 1, "heap fragmented");
 +    p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2);
 +    test_assert(p1 == NULL, "allocation not failed");
    }
 -  /* [11.1.3] Creating thread 1, it is expected to succeed.*/
 +  /* [11.1.3] Single block allocation using chHeapAlloc() then the
 +     block is freed using chHeapFree(), must not fail.*/
    test_set_step(3);
    {
 -    threads[0] = chThdCreateFromHeap(&heap1,
 -                                     THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
 -                                     "dyn1",
 -                                     prio-1, dyn_thread1, "A");
 -    test_assert(threads[0] != NULL, "thread creation failed");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    test_assert(p1 != NULL, "allocation failed");
 +    chHeapFree(p1);
    }
 -  /* [11.1.4] Creating thread 2, it is expected to succeed.*/
 +  /* [11.1.4] Using chHeapStatus() to assess the heap state. There must
 +     be at least one free block of sufficient size.*/
    test_set_step(4);
    {
 -    threads[1] = chThdCreateFromHeap(&heap1,
 -                                     THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
 -                                     "dyn2",
 -                                     prio-2, dyn_thread1, "B");
 -    test_assert(threads[1] != NULL, "thread creation failed");
 +    size_t total_size, largest_size;
 +
 +    n = chHeapStatus(&test_heap, &total_size, &largest_size);
 +    test_assert(n == 1, "missing free block");
 +    test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
 +    test_assert(total_size == largest_size, "unexpected heap state");
    }
 -  /* [11.1.5] Creating thread 3, it is expected to fail.*/
 +  /* [11.1.5] Allocating then freeing in the same order.*/
    test_set_step(5);
    {
 -    threads[2] = chThdCreateFromHeap(&heap1,
 -                                     THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 1024),
 -                                     "dyn3",
 -                                     prio-3, dyn_thread1, "C");
 -    test_assert(threads[2] == NULL, "thread creation not failed");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p1);                                 /* Does not merge.*/
 +    chHeapFree(p2);                                 /* Merges backward.*/
 +    chHeapFree(p3);                                 /* Merges both sides.*/
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
    }
 -  /* [11.1.6] Letting threads execute then checking the start order and
 -     freeing memory.*/
 +  /* [11.1.6] Allocating then freeing in reverse order.*/
    test_set_step(6);
    {
 -    test_wait_threads();
 -    test_assert_sequence("AB", "invalid sequence");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p3);                                 /* Merges forward.*/
 +    chHeapFree(p2);                                 /* Merges forward.*/
 +    chHeapFree(p1);                                 /* Merges forward.*/
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
    }
 -  /* [11.1.7] Getting heap info again for verification.*/
 +  /* [11.1.7] Small fragments handling. Checking the behavior when
 +     allocating blocks with size not multiple of alignment unit.*/
    test_set_step(7);
    {
 -    n2 = chHeapStatus(&heap1, &total2, &largest2);
 -    test_assert(n1 == n2, "fragmentation changed");
 -    test_assert(total1 == total2, "total free space changed");
 -    test_assert(largest1 == largest2, "largest fragment size changed");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p1);
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    /* Note, the first situation happens when the alignment size is smaller
 +       than the header size, the second in the other cases.*/
 +    test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
 +                (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
 +    chHeapFree(p2);
 +    chHeapFree(p1);
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [11.1.8] Skipping a fragment, the first fragment in the list is
 +     too small so the allocator must pick the second one.*/
 +  test_set_step(8);
 +  {
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    chHeapFree(p1);
 +    test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
 +    chHeapFree(p1);
 +    chHeapFree(p2);
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +  }
 +
 +  /* [11.1.9] Allocating the whole available space.*/
 +  test_set_step(9);
 +  {
 +    (void)chHeapStatus(&test_heap, &n, NULL);
 +    p1 = chHeapAlloc(&test_heap, n);
 +    test_assert(p1 != NULL, "allocation failed");
 +    test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
 +    chHeapFree(p1);
 +  }
 +
 +  /* [11.1.10] Testing final conditions. The heap geometry must be the
 +     same than the one registered at beginning.*/
 +  test_set_step(10);
 +  {
 +    test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
 +    test_assert(n == sz, "size changed");
    }
  }
  static const testcase_t test_011_001 = {
 -  "Threads creation from Memory Heap",
 +  "Allocation and fragmentation",
    test_011_001_setup,
    NULL,
    test_011_001_execute
  };
 -#endif /* CH_CFG_USE_HEAP */
 -#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
  /**
 - * @page test_011_002 [11.2] Threads creation from Memory Pool
 + * @page test_011_002 [11.2] Default Heap
   *
   * <h2>Description</h2>
 - * Five thread creation are attempted from a pool containing only four
 - * elements.<br> The test expects the first four threads to
 - * successfully start and the last one to fail.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_MEMPOOLS
 - * .
 + * The default heap is pre-allocated in the system. We test base
 + * functionality.
   *
   * <h2>Test Steps</h2>
 - * - [11.2.1] Adding four working areas to the pool.
 - * - [11.2.2] Getting base priority for threads.
 - * - [11.2.3] Creating the five threads.
 - * - [11.2.4] Testing that only the fifth thread creation failed.
 - * - [11.2.5] Letting them run, free the memory then checking the
 - *   execution sequence.
 - * - [11.2.6] Testing that the pool contains four elements again.
 + * - [11.2.1] Single block allocation using chHeapAlloc() then the
 + *   block is freed using chHeapFree(), must not fail.
 + * - [11.2.2] Testing allocation failure.
   * .
   */
 -static void test_011_002_setup(void) {
 -  chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
 -}
 -
  static void test_011_002_execute(void) {
 -  unsigned i;
 -  tprio_t prio;
 +  void *p1;
 +  size_t total_size, largest_size;
 -  /* [11.2.1] Adding four working areas to the pool.*/
 +  /* [11.2.1] Single block allocation using chHeapAlloc() then the
 +     block is freed using chHeapFree(), must not fail.*/
    test_set_step(1);
    {
 -    for (i = 0; i < 4; i++)
 -      chPoolFree(&mp1, wa[i]);
 +    (void)chHeapStatus(NULL, &total_size, &largest_size);
 +    p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
 +    test_assert(p1 != NULL, "allocation failed");
 +    chHeapFree(p1);
    }
 -  /* [11.2.2] Getting base priority for threads.*/
 +  /* [11.2.2] Testing allocation failure.*/
    test_set_step(2);
    {
 -    prio = chThdGetPriorityX();
 -  }
 -
 -  /* [11.2.3] Creating the five threads.*/
 -  test_set_step(3);
 -  {
 -    threads[0] = chThdCreateFromMemoryPool(&mp1, "dyn1", prio-1, dyn_thread1, "A");
 -    threads[1] = chThdCreateFromMemoryPool(&mp1, "dyn2", prio-2, dyn_thread1, "B");
 -    threads[2] = chThdCreateFromMemoryPool(&mp1, "dyn3", prio-3, dyn_thread1, "C");
 -    threads[3] = chThdCreateFromMemoryPool(&mp1, "dyn4", prio-4, dyn_thread1, "D");
 -    threads[4] = chThdCreateFromMemoryPool(&mp1, "dyn5", prio-5, dyn_thread1, "E");
 -  }
 -
 -  /* [11.2.4] Testing that only the fifth thread creation failed.*/
 -  test_set_step(4);
 -  {
 -    test_assert((threads[0] != NULL) &&
 -                (threads[1] != NULL) &&
 -                (threads[2] != NULL) &&
 -                (threads[3] != NULL),
 -                "thread creation failed");
 -    test_assert(threads[4] == NULL,
 -                "thread creation not failed");
 -  }
 -
 -  /* [11.2.5] Letting them run, free the memory then checking the
 -     execution sequence.*/
 -  test_set_step(5);
 -  {
 -    test_wait_threads();
 -    test_assert_sequence("ABCD", "invalid sequence");
 -  }
 -
 -  /* [11.2.6] Testing that the pool contains four elements again.*/
 -  test_set_step(6);
 -  {
 -    for (i = 0; i < 4; i++)
 -      test_assert(chPoolAlloc(&mp1) != NULL, "pool list empty");
 -    test_assert(chPoolAlloc(&mp1) == NULL, "pool list not empty");
 +    p1 = chHeapAlloc(NULL, (size_t)-256);
 +    test_assert(p1 == NULL, "allocation not failed");
    }
  }
  static const testcase_t test_011_002 = {
 -  "Threads creation from Memory Pool",
 -  test_011_002_setup,
 +  "Default Heap",
 +  NULL,
    NULL,
    test_011_002_execute
  };
 -#endif /* CH_CFG_USE_MEMPOOLS */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Dynamic threads.
 + * @brief   Memory Heaps.
   */
  const testcase_t * const test_sequence_011[] = {
 -#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
    &test_011_001,
 -#endif
 -#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
    &test_011_002,
 -#endif
    NULL
  };
 -#endif /* CH_CFG_USE_DYNAMIC */
 +#endif /* CH_CFG_USE_HEAP */
 diff --git a/test/rt/source/test/test_sequence_012.c b/test/rt/source/test/test_sequence_012.c index 1ce965916..834239758 100644 --- a/test/rt/source/test/test_sequence_012.c +++ b/test/rt/source/test/test_sequence_012.c @@ -22,1010 +22,263 @@   * @file    test_sequence_012.c
   * @brief   Test Sequence 012 code.
   *
 - * @page test_sequence_012 [12] Benchmarks
 + * @page test_sequence_012 [12] Dynamic threads
   *
   * File: @ref test_sequence_012.c
   *
   * <h2>Description</h2>
 - * This module implements a series of system benchmarks. The benchmarks
 - * are useful as a stress test and as a reference when comparing
 - * ChibiOS/RT with similar systems.<br> Objective of the test sequence
 - * is to provide a performance index for the most critical system
 - * subsystems. The performance numbers allow to discover performance
 - * regressions between successive ChibiOS/RT releases.
 + * This module implements the test sequence for the dynamic thread
 + * creation APIs.
 + *
 + * <h2>Conditions</h2>
 + * This sequence is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_DYNAMIC
 + * .
   *
   * <h2>Test Cases</h2>
   * - @subpage test_012_001
   * - @subpage test_012_002
 - * - @subpage test_012_003
 - * - @subpage test_012_004
 - * - @subpage test_012_005
 - * - @subpage test_012_006
 - * - @subpage test_012_007
 - * - @subpage test_012_008
 - * - @subpage test_012_009
 - * - @subpage test_012_010
 - * - @subpage test_012_011
 - * - @subpage test_012_012
   * .
   */
 +#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
 +
  /****************************************************************************
   * Shared code.
   ****************************************************************************/
 -#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
 -static semaphore_t sem1;
 -#endif
 -#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
 -static mutex_t mtx1;
 -#endif
 -
 -static void tmo(void *param) {(void)param;}
 -
 -#if CH_CFG_USE_MESSAGES
 -static THD_FUNCTION(bmk_thread1, p) {
 -  thread_t *tp;
 -  msg_t msg;
 -
 -  (void)p;
 -  do {
 -    tp = chMsgWait();
 -    msg = chMsgGet(tp);
 -    chMsgRelease(tp, msg);
 -  } while (msg);
 -}
 -
 -NOINLINE static unsigned int msg_loop_test(thread_t *tp) {
 -  systime_t start, end;
 -
 -  uint32_t n = 0;
 -  start = test_wait_tick();
 -  end = start + MS2ST(1000);
 -  do {
 -    (void)chMsgSend(tp, 1);
 -    n++;
 -#if defined(SIMULATOR)
 -    _sim_check_for_interrupts();
 +#if CH_CFG_USE_HEAP
 +static memory_heap_t heap1;
  #endif
 -  } while (chVTIsSystemTimeWithinX(start, end));
 -  (void)chMsgSend(tp, 0);
 -  return n;
 -}
 +#if CH_CFG_USE_MEMPOOLS
 +static memory_pool_t mp1;
  #endif
 -static THD_FUNCTION(bmk_thread3, p) {
 -
 -  chThdExit((msg_t)p);
 -}
 -
 -static THD_FUNCTION(bmk_thread4, p) {
 -  msg_t msg;
 -  thread_t *self = chThdGetSelfX();
 +static THD_FUNCTION(dyn_thread1, p) {
 -  (void)p;
 -  chSysLock();
 -  do {
 -    chSchGoSleepS(CH_STATE_SUSPENDED);
 -    msg = self->u.rdymsg;
 -  } while (msg == MSG_OK);
 -  chSysUnlock();
 -}
 -
 -#if CH_CFG_USE_SEMAPHORES
 -static THD_FUNCTION(bmk_thread7, p) {
 -
 -  (void)p;
 -  while (!chThdShouldTerminateX())
 -    chSemWait(&sem1);
 -}
 -#endif
 -
 -static THD_FUNCTION(bmk_thread8, p) {
 -
 -  do {
 -    chThdYield();
 -    chThdYield();
 -    chThdYield();
 -    chThdYield();
 -    (*(uint32_t *)p) += 4;
 -#if defined(SIMULATOR)
 -    _sim_check_for_interrupts();
 -#endif
 -  } while(!chThdShouldTerminateX());
 +  test_emit_token(*(char *)p);
  }
  /****************************************************************************
   * Test cases.
   ****************************************************************************/
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 -/**
 - * @page test_012_001 [12.1] Messages performance #1
 - *
 - * <h2>Description</h2>
 - * A message server thread is created with a lower priority than the
 - * client thread, the messages throughput per second is measured and
 - * the result printed on the output log.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_MESSAGES
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [12.1.1] The messenger thread is started at a lower priority than
 - *   the current thread.
 - * - [12.1.2] The number of messages exchanged is counted in a one
 - *   second time window.
 - * - [12.1.3] Score is printed.
 - * .
 - */
 -
 -static void test_012_001_execute(void) {
 -  uint32_t n;
 -
 -  /* [12.1.1] The messenger thread is started at a lower priority than
 -     the current thread.*/
 -  test_set_step(1);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread1, NULL);
 -  }
 -
 -  /* [12.1.2] The number of messages exchanged is counted in a one
 -     second time window.*/
 -  test_set_step(2);
 -  {
 -    n = msg_loop_test(threads[0]);
 -    test_wait_threads();
 -  }
 -
 -  /* [12.1.3] Score is printed.*/
 -  test_set_step(3);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_print(" msgs/S, ");
 -    test_printn(n << 1);
 -    test_println(" ctxswc/S");
 -  }
 -}
 -
 -static const testcase_t test_012_001 = {
 -  "Messages performance #1",
 -  NULL,
 -  NULL,
 -  test_012_001_execute
 -};
 -#endif /* CH_CFG_USE_MESSAGES */
 -
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
  /**
 - * @page test_012_002 [12.2] Messages performance #2
 + * @page test_012_001 [12.1] Threads creation from Memory Heap
   *
   * <h2>Description</h2>
 - * A message server thread is created with an higher priority than the
 - * client thread, the messages throughput per second is measured and
 - * the result printed on the output log.
 + * Two threads are started by allocating the memory from the Memory
 + * Heap then a third thread is started with a huge stack
 + * requirement.<br> The test expects the first two threads to
 + * successfully start and the third one to fail.
   *
   * <h2>Conditions</h2>
   * This test is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MESSAGES
 + * - CH_CFG_USE_HEAP
   * .
   *
   * <h2>Test Steps</h2>
 - * - [12.2.1] The messenger thread is started at an higher priority
 - *   than the current thread.
 - * - [12.2.2] The number of messages exchanged is counted in a one
 - *   second time window.
 - * - [12.2.3] Score is printed.
 + * - [12.1.1] Getting base priority for threads.
 + * - [12.1.2] Getting heap info before the test.
 + * - [12.1.3] Creating thread 1, it is expected to succeed.
 + * - [12.1.4] Creating thread 2, it is expected to succeed.
 + * - [12.1.5] Creating thread 3, it is expected to fail.
 + * - [12.1.6] Letting threads execute then checking the start order and
 + *   freeing memory.
 + * - [12.1.7] Getting heap info again for verification.
   * .
   */
 -static void test_012_002_execute(void) {
 -  uint32_t n;
 -
 -  /* [12.2.1] The messenger thread is started at an higher priority
 -     than the current thread.*/
 -  test_set_step(1);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL);
 -  }
 -
 -  /* [12.2.2] The number of messages exchanged is counted in a one
 -     second time window.*/
 -  test_set_step(2);
 -  {
 -    n = msg_loop_test(threads[0]);
 -    test_wait_threads();
 -  }
 -
 -  /* [12.2.3] Score is printed.*/
 -  test_set_step(3);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_print(" msgs/S, ");
 -    test_printn(n << 1);
 -    test_println(" ctxswc/S");
 -  }
 +static void test_012_001_setup(void) {
 +  chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
  }
 -static const testcase_t test_012_002 = {
 -  "Messages performance #2",
 -  NULL,
 -  NULL,
 -  test_012_002_execute
 -};
 -#endif /* CH_CFG_USE_MESSAGES */
 -
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 -/**
 - * @page test_012_003 [12.3] Messages performance #3
 - *
 - * <h2>Description</h2>
 - * A message server thread is created with an higher priority than the
 - * client thread, four lower priority threads crowd the ready list, the
 - * messages throughput per second is measured while the ready list and
 - * the result printed on the output log.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_MESSAGES
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [12.3.1] The messenger thread is started at an higher priority
 - *   than the current thread.
 - * - [12.3.2] Four threads are started at a lower priority than the
 - *   current thread.
 - * - [12.3.3] The number of messages exchanged is counted in a one
 - *   second time window.
 - * - [12.3.4] Score is printed.
 - * .
 - */
 -
 -static void test_012_003_execute(void) {
 -  uint32_t n;
 -
 -  /* [12.3.1] The messenger thread is started at an higher priority
 -     than the current thread.*/
 -  test_set_step(1);
 -  {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL);
 -  }
 -
 -  /* [12.3.2] Four threads are started at a lower priority than the
 -     current thread.*/
 -  test_set_step(2);
 -  {
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, bmk_thread3, NULL);
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, bmk_thread3, NULL);
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-4, bmk_thread3, NULL);
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-5, bmk_thread3, NULL);
 -  }
 -
 -  /* [12.3.3] The number of messages exchanged is counted in a one
 -     second time window.*/
 -  test_set_step(3);
 -  {
 -    n = msg_loop_test(threads[0]);
 -    test_wait_threads();
 -  }
 -
 -  /* [12.3.4] Score is printed.*/
 -  test_set_step(4);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_print(" msgs/S, ");
 -    test_printn(n << 1);
 -    test_println(" ctxswc/S");
 -  }
 -}
 -
 -static const testcase_t test_012_003 = {
 -  "Messages performance #3",
 -  NULL,
 -  NULL,
 -  test_012_003_execute
 -};
 -#endif /* CH_CFG_USE_MESSAGES */
 -
 -/**
 - * @page test_012_004 [12.4] Context Switch performance
 - *
 - * <h2>Description</h2>
 - * A thread is created that just performs a @p chSchGoSleepS() into a
 - * loop, the thread is awakened as fast is possible by the tester
 - * thread.<br> The Context Switch performance is calculated by
 - * measuring the number of iterations after a second of continuous
 - * operations.
 - *
 - * <h2>Test Steps</h2>
 - * - [12.4.1] Starting the target thread at an higher priority level.
 - * - [12.4.2] Waking up the thread as fast as possible in a one second
 - *   time window.
 - * - [12.4.3] Stopping the target thread.
 - * - [12.4.4] Score is printed.
 - * .
 - */
 -
 -static void test_012_004_execute(void) {
 -  thread_t *tp;
 -  uint32_t n;
 -
 -  /* [12.4.1] Starting the target thread at an higher priority level.*/
 -  test_set_step(1);
 -  {
 -    tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1,
 -                                        bmk_thread4, NULL);
 -  }
 -
 -  /* [12.4.2] Waking up the thread as fast as possible in a one second
 -     time window.*/
 -  test_set_step(2);
 -  {
 -    systime_t start, end;
 -
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -      chSysLock();
 -      chSchWakeupS(tp, MSG_OK);
 -      chSchWakeupS(tp, MSG_OK);
 -      chSchWakeupS(tp, MSG_OK);
 -      chSchWakeupS(tp, MSG_OK);
 -      chSysUnlock();
 -      n += 4;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 -  }
 -
 -  /* [12.4.3] Stopping the target thread.*/
 -  test_set_step(3);
 -  {
 -    chSysLock();
 -    chSchWakeupS(tp, MSG_TIMEOUT);
 -    chSysUnlock();
 -    test_wait_threads();
 -  }
 -
 -  /* [12.4.4] Score is printed.*/
 -  test_set_step(4);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n * 2);
 -    test_println(" ctxswc/S");
 -  }
 -}
 -
 -static const testcase_t test_012_004 = {
 -  "Context Switch performance",
 -  NULL,
 -  NULL,
 -  test_012_004_execute
 -};
 -
 -/**
 - * @page test_012_005 [12.5] Threads performance, full cycle
 - *
 - * <h2>Description</h2>
 - * Threads are continuously created and terminated into a loop. A full
 - * chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is
 - * performed in each iteration.<br> The performance is calculated by
 - * measuring the number of iterations after a second of continuous
 - * operations.
 - *
 - * <h2>Test Steps</h2>
 - * - [12.5.1] A thread is created at a lower priority level and its
 - *   termination detected using @p chThdWait(). The operation is
 - *   repeated continuously in a one-second time window.
 - * - [12.5.2] Score is printed.
 - * .
 - */
 -
 -static void test_012_005_execute(void) {
 -  uint32_t n;
 -  tprio_t prio = chThdGetPriorityX() - 1;
 -  systime_t start, end;
 -
 -  /* [12.5.1] A thread is created at a lower priority level and its
 -     termination detected using @p chThdWait(). The operation is
 -     repeated continuously in a one-second time window.*/
 -  test_set_step(1);
 -  {
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -      chThdWait(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL));
 -      n++;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 -  }
 -
 -  /* [12.5.2] Score is printed.*/
 -  test_set_step(2);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_println(" threads/S");
 -  }
 -}
 -
 -static const testcase_t test_012_005 = {
 -  "Threads performance, full cycle",
 -  NULL,
 -  NULL,
 -  test_012_005_execute
 -};
 -
 -/**
 - * @page test_012_006 [12.6] Threads performance, create/exit only
 - *
 - * <h2>Description</h2>
 - * Threads are continuously created and terminated into a loop. A
 - * partial @p chThdCreateStatic() / @p chThdExit() cycle is performed
 - * in each iteration, the @p chThdWait() is not necessary because the
 - * thread is created at an higher priority so there is no need to wait
 - * for it to terminate.<br> The performance is calculated by measuring
 - * the number of iterations after a second of continuous operations.
 - *
 - * <h2>Test Steps</h2>
 - * - [12.6.1] A thread is created at an higher priority level and let
 - *   terminate immediately. The operation is repeated continuously in a
 - *   one-second time window.
 - * - [12.6.2] Score is printed.
 - * .
 - */
 -
 -static void test_012_006_execute(void) {
 -  uint32_t n;
 -  tprio_t prio = chThdGetPriorityX() + 1;
 -  systime_t start, end;
 -
 -  /* [12.6.1] A thread is created at an higher priority level and let
 -     terminate immediately. The operation is repeated continuously in a
 -     one-second time window.*/
 -  test_set_step(1);
 -  {
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -#if CH_CFG_USE_REGISTRY
 -      chThdRelease(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL));
 -#else
 -      chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL);
 -#endif
 -      n++;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 -  }
 -
 -  /* [12.6.2] Score is printed.*/
 -  test_set_step(2);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_println(" threads/S");
 -  }
 -}
 -
 -static const testcase_t test_012_006 = {
 -  "Threads performance, create/exit only",
 -  NULL,
 -  NULL,
 -  test_012_006_execute
 -};
 -
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 -/**
 - * @page test_012_007 [12.7] Mass reschedule performance
 - *
 - * <h2>Description</h2>
 - * Five threads are created and atomically rescheduled by resetting the
 - * semaphore where they are waiting on. The operation is performed into
 - * a continuous loop.<br> The performance is calculated by measuring
 - * the number of iterations after a second of continuous operations.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [12.7.1] Five threads are created at higher priority that
 - *   immediately enqueue on a semaphore.
 - * - [12.7.2] The semaphore is reset waking up the five threads. The
 - *   operation is repeated continuously in a one-second time window.
 - * - [12.7.3] The five threads are terminated.
 - * - [12.7.4] The score is printed.
 - * .
 - */
 -
 -static void test_012_007_setup(void) {
 -  chSemObjectInit(&sem1, 0);
 -}
 -
 -static void test_012_007_execute(void) {
 -  uint32_t n;
 +static void test_012_001_execute(void) {
 +  size_t n1, total1, largest1;
 +  size_t n2, total2, largest2;
 +  tprio_t prio;
 -  /* [12.7.1] Five threads are created at higher priority that
 -     immediately enqueue on a semaphore.*/
 +  /* [12.1.1] Getting base priority for threads.*/
    test_set_step(1);
    {
 -    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, bmk_thread7, NULL);
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, bmk_thread7, NULL);
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, bmk_thread7, NULL);
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, bmk_thread7, NULL);
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, bmk_thread7, NULL);
 +    prio = chThdGetPriorityX();
    }
 -  /* [12.7.2] The semaphore is reset waking up the five threads. The
 -     operation is repeated continuously in a one-second time window.*/
 +  /* [12.1.2] Getting heap info before the test.*/
    test_set_step(2);
    {
 -    systime_t start, end;
 -
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -      chSemReset(&sem1, 0);
 -      n++;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 +    n1 = chHeapStatus(&heap1, &total1, &largest1);
 +    test_assert(n1 == 1, "heap fragmented");
    }
 -  /* [12.7.3] The five threads are terminated.*/
 +  /* [12.1.3] Creating thread 1, it is expected to succeed.*/
    test_set_step(3);
    {
 -    test_terminate_threads();
 -    chSemReset(&sem1, 0);
 -    test_wait_threads();
 +    threads[0] = chThdCreateFromHeap(&heap1,
 +                                     THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
 +                                     "dyn1",
 +                                     prio-1, dyn_thread1, "A");
 +    test_assert(threads[0] != NULL, "thread creation failed");
    }
 -  /* [12.7.4] The score is printed.*/
 +  /* [12.1.4] Creating thread 2, it is expected to succeed.*/
    test_set_step(4);
    {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_print(" reschedules/S, ");
 -    test_printn(n * 6);
 -    test_println(" ctxswc/S");
 +    threads[1] = chThdCreateFromHeap(&heap1,
 +                                     THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
 +                                     "dyn2",
 +                                     prio-2, dyn_thread1, "B");
 +    test_assert(threads[1] != NULL, "thread creation failed");
    }
 -}
 -
 -static const testcase_t test_012_007 = {
 -  "Mass reschedule performance",
 -  test_012_007_setup,
 -  NULL,
 -  test_012_007_execute
 -};
 -#endif /* CH_CFG_USE_SEMAPHORES */
 -/**
 - * @page test_012_008 [12.8] Round-Robin voluntary reschedule
 - *
 - * <h2>Description</h2>
 - * Five threads are created at equal priority, each thread just
 - * increases a variable and yields.<br> The performance is calculated
 - * by measuring the number of iterations after a second of continuous
 - * operations.
 - *
 - * <h2>Test Steps</h2>
 - * - [12.8.1] The five threads are created at lower priority. The
 - *   threds have equal priority and start calling @p chThdYield()
 - *   continuously.
 - * - [12.8.2] Waiting one second then terminating the 5 threads.
 - * - [12.8.3] The score is printed.
 - * .
 - */
 -
 -static void test_012_008_execute(void) {
 -  uint32_t n;
 -
 -  /* [12.8.1] The five threads are created at lower priority. The
 -     threds have equal priority and start calling @p chThdYield()
 -     continuously.*/
 -  test_set_step(1);
 +  /* [12.1.5] Creating thread 3, it is expected to fail.*/
 +  test_set_step(5);
    {
 -    n = 0;
 -    test_wait_tick();threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 -
 -    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 -    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 -    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 -    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 +    threads[2] = chThdCreateFromHeap(&heap1,
 +                                     THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 1024),
 +                                     "dyn3",
 +                                     prio-3, dyn_thread1, "C");
 +    test_assert(threads[2] == NULL, "thread creation not failed");
    }
 -  /* [12.8.2] Waiting one second then terminating the 5 threads.*/
 -  test_set_step(2);
 +  /* [12.1.6] Letting threads execute then checking the start order and
 +     freeing memory.*/
 +  test_set_step(6);
    {
 -    chThdSleepSeconds(1);
 -    test_terminate_threads();
      test_wait_threads();
 +    test_assert_sequence("AB", "invalid sequence");
    }
 -  /* [12.8.3] The score is printed.*/
 -  test_set_step(3);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n);
 -    test_println(" ctxswc/S");
 -  }
 -}
 -
 -static const testcase_t test_012_008 = {
 -  "Round-Robin voluntary reschedule",
 -  NULL,
 -  NULL,
 -  test_012_008_execute
 -};
 -
 -/**
 - * @page test_012_009 [12.9] Virtual Timers set/reset performance
 - *
 - * <h2>Description</h2>
 - * A virtual timer is set and immediately reset into a continuous
 - * loop.<br> The performance is calculated by measuring the number of
 - * iterations after a second of continuous operations.
 - *
 - * <h2>Test Steps</h2>
 - * - [12.9.1] Two timers are set then reset without waiting for their
 - *   counter to elapse. The operation is repeated continuously in a
 - *   one-second time window.
 - * - [12.9.2] The score is printed.
 - * .
 - */
 -
 -static void test_012_009_execute(void) {
 -  static virtual_timer_t vt1, vt2;
 -  uint32_t n;
 -
 -  /* [12.9.1] Two timers are set then reset without waiting for their
 -     counter to elapse. The operation is repeated continuously in a
 -     one-second time window.*/
 -  test_set_step(1);
 -  {
 -    systime_t start, end;
 -
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -      chSysLock();
 -      chVTDoSetI(&vt1, 1, tmo, NULL);
 -      chVTDoSetI(&vt2, 10000, tmo, NULL);
 -      chVTDoResetI(&vt1);
 -      chVTDoResetI(&vt2);
 -      chSysUnlock();
 -      n++;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 -  }
 -
 -  /* [12.9.2] The score is printed.*/
 -  test_set_step(2);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n * 2);
 -    test_println(" timers/S");
 -  }
 -}
 -
 -static const testcase_t test_012_009 = {
 -  "Virtual Timers set/reset performance",
 -  NULL,
 -  NULL,
 -  test_012_009_execute
 -};
 -
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 -/**
 - * @page test_012_010 [12.10] Semaphores wait/signal performance
 - *
 - * <h2>Description</h2>
 - * A counting semaphore is taken/released into a continuous loop, no
 - * Context Switch happens because the counter is always non
 - * negative.<br> The performance is calculated by measuring the number
 - * of iterations after a second of continuous operations.
 - *
 - * <h2>Conditions</h2>
 - * This test is only executed if the following preprocessor condition
 - * evaluates to true:
 - * - CH_CFG_USE_SEMAPHORES
 - * .
 - *
 - * <h2>Test Steps</h2>
 - * - [12.10.1] A semaphore is teken and released. The operation is
 - *   repeated continuously in a one-second time window.
 - * - [12.10.2] The score is printed.
 - * .
 - */
 -
 -static void test_012_010_setup(void) {
 -  chSemObjectInit(&sem1, 1);
 -}
 -
 -static void test_012_010_execute(void) {
 -  uint32_t n;
 -
 -  /* [12.10.1] A semaphore is teken and released. The operation is
 -     repeated continuously in a one-second time window.*/
 -  test_set_step(1);
 -  {
 -    systime_t start, end;
 -
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -      chSemWait(&sem1);
 -      chSemSignal(&sem1);
 -      chSemWait(&sem1);
 -      chSemSignal(&sem1);
 -      chSemWait(&sem1);
 -      chSemSignal(&sem1);
 -      chSemWait(&sem1);
 -      chSemSignal(&sem1);
 -      n++;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 -  }
 -
 -  /* [12.10.2] The score is printed.*/
 -  test_set_step(2);
 +  /* [12.1.7] Getting heap info again for verification.*/
 +  test_set_step(7);
    {
 -    test_print("--- Score : ");
 -    test_printn(n * 4);
 -    test_println(" wait+signal/S");
 +    n2 = chHeapStatus(&heap1, &total2, &largest2);
 +    test_assert(n1 == n2, "fragmentation changed");
 +    test_assert(total1 == total2, "total free space changed");
 +    test_assert(largest1 == largest2, "largest fragment size changed");
    }
  }
 -static const testcase_t test_012_010 = {
 -  "Semaphores wait/signal performance",
 -  test_012_010_setup,
 +static const testcase_t test_012_001 = {
 +  "Threads creation from Memory Heap",
 +  test_012_001_setup,
    NULL,
 -  test_012_010_execute
 +  test_012_001_execute
  };
 -#endif /* CH_CFG_USE_SEMAPHORES */
 +#endif /* CH_CFG_USE_HEAP */
 -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
  /**
 - * @page test_012_011 [12.11] Mutexes lock/unlock performance
 + * @page test_012_002 [12.2] Threads creation from Memory Pool
   *
   * <h2>Description</h2>
 - * A mutex is locked/unlocked into a continuous loop, no Context Switch
 - * happens because there are no other threads asking for the mutex.<br>
 - * The performance is calculated by measuring the number of iterations
 - * after a second of continuous operations.
 + * Five thread creation are attempted from a pool containing only four
 + * elements.<br> The test expects the first four threads to
 + * successfully start and the last one to fail.
   *
   * <h2>Conditions</h2>
   * This test is only executed if the following preprocessor condition
   * evaluates to true:
 - * - CH_CFG_USE_MUTEXES
 + * - CH_CFG_USE_MEMPOOLS
   * .
   *
   * <h2>Test Steps</h2>
 - * - [12.11.1] A mutex is locked and unlocked. The operation is
 - *   repeated continuously in a one-second time window.
 - * - [12.11.2] The score is printed.
 + * - [12.2.1] Adding four working areas to the pool.
 + * - [12.2.2] Getting base priority for threads.
 + * - [12.2.3] Creating the five threads.
 + * - [12.2.4] Testing that only the fifth thread creation failed.
 + * - [12.2.5] Letting them run, free the memory then checking the
 + *   execution sequence.
 + * - [12.2.6] Testing that the pool contains four elements again.
   * .
   */
 -static void test_012_011_setup(void) {
 -  chMtxObjectInit(&mtx1);
 +static void test_012_002_setup(void) {
 +  chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
  }
 -static void test_012_011_execute(void) {
 -  uint32_t n;
 -
 -  /* [12.11.1] A mutex is locked and unlocked. The operation is
 -     repeated continuously in a one-second time window.*/
 -  test_set_step(1);
 -  {
 -    systime_t start, end;
 -
 -    n = 0;
 -    start = test_wait_tick();
 -    end = start + MS2ST(1000);
 -    do {
 -      chMtxLock(&mtx1);
 -      chMtxUnlock(&mtx1);
 -      chMtxLock(&mtx1);
 -      chMtxUnlock(&mtx1);
 -      chMtxLock(&mtx1);
 -      chMtxUnlock(&mtx1);
 -      chMtxLock(&mtx1);
 -      chMtxUnlock(&mtx1);
 -      n++;
 -#if defined(SIMULATOR)
 -      _sim_check_for_interrupts();
 -#endif
 -    } while (chVTIsSystemTimeWithinX(start, end));
 -  }
 -
 -  /* [12.11.2] The score is printed.*/
 -  test_set_step(2);
 -  {
 -    test_print("--- Score : ");
 -    test_printn(n * 4);
 -    test_println(" lock+unlock/S");
 -  }
 -}
 -
 -static const testcase_t test_012_011 = {
 -  "Mutexes lock/unlock performance",
 -  test_012_011_setup,
 -  NULL,
 -  test_012_011_execute
 -};
 -#endif /* CH_CFG_USE_MUTEXES */
 -
 -/**
 - * @page test_012_012 [12.12] RAM Footprint
 - *
 - * <h2>Description</h2>
 - * The memory size of the various kernel objects is printed.
 - *
 - * <h2>Test Steps</h2>
 - * - [12.12.1] The size of the system area is printed.
 - * - [12.12.2] The size of a thread structure is printed.
 - * - [12.12.3] The size of a virtual timer structure is printed.
 - * - [12.12.4] The size of a semaphore structure is printed.
 - * - [12.12.5] The size of a mutex is printed.
 - * - [12.12.6] The size of a condition variable is printed.
 - * - [12.12.7] The size of an event source is printed.
 - * - [12.12.8] The size of an event listener is printed.
 - * - [12.12.9] The size of a mailbox is printed.
 - * .
 - */
 -
 -static void test_012_012_execute(void) {
 +static void test_012_002_execute(void) {
 +  unsigned i;
 +  tprio_t prio;
 -  /* [12.12.1] The size of the system area is printed.*/
 +  /* [12.2.1] Adding four working areas to the pool.*/
    test_set_step(1);
    {
 -    test_print("--- System: ");
 -    test_printn(sizeof(ch_system_t));
 -    test_println(" bytes");
 +    for (i = 0; i < 4; i++)
 +      chPoolFree(&mp1, wa[i]);
    }
 -  /* [12.12.2] The size of a thread structure is printed.*/
 +  /* [12.2.2] Getting base priority for threads.*/
    test_set_step(2);
    {
 -    test_print("--- Thread: ");
 -    test_printn(sizeof(thread_t));
 -    test_println(" bytes");
 +    prio = chThdGetPriorityX();
    }
 -  /* [12.12.3] The size of a virtual timer structure is printed.*/
 +  /* [12.2.3] Creating the five threads.*/
    test_set_step(3);
    {
 -    test_print("--- Timer : ");
 -    test_printn(sizeof(virtual_timer_t));
 -    test_println(" bytes");
 +    threads[0] = chThdCreateFromMemoryPool(&mp1, "dyn1", prio-1, dyn_thread1, "A");
 +    threads[1] = chThdCreateFromMemoryPool(&mp1, "dyn2", prio-2, dyn_thread1, "B");
 +    threads[2] = chThdCreateFromMemoryPool(&mp1, "dyn3", prio-3, dyn_thread1, "C");
 +    threads[3] = chThdCreateFromMemoryPool(&mp1, "dyn4", prio-4, dyn_thread1, "D");
 +    threads[4] = chThdCreateFromMemoryPool(&mp1, "dyn5", prio-5, dyn_thread1, "E");
    }
 -  /* [12.12.4] The size of a semaphore structure is printed.*/
 +  /* [12.2.4] Testing that only the fifth thread creation failed.*/
    test_set_step(4);
    {
 -#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
 -    test_print("--- Semaph: ");
 -    test_printn(sizeof(semaphore_t));
 -    test_println(" bytes");
 -#endif
 +    test_assert((threads[0] != NULL) &&
 +                (threads[1] != NULL) &&
 +                (threads[2] != NULL) &&
 +                (threads[3] != NULL),
 +                "thread creation failed");
 +    test_assert(threads[4] == NULL,
 +                "thread creation not failed");
    }
 -  /* [12.12.5] The size of a mutex is printed.*/
 +  /* [12.2.5] Letting them run, free the memory then checking the
 +     execution sequence.*/
    test_set_step(5);
    {
 -#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
 -    test_print("--- Mutex : ");
 -    test_printn(sizeof(mutex_t));
 -    test_println(" bytes");
 -#endif
 +    test_wait_threads();
 +    test_assert_sequence("ABCD", "invalid sequence");
    }
 -  /* [12.12.6] The size of a condition variable is printed.*/
 +  /* [12.2.6] Testing that the pool contains four elements again.*/
    test_set_step(6);
    {
 -#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
 -    test_print("--- CondV.: ");
 -    test_printn(sizeof(condition_variable_t));
 -    test_println(" bytes");
 -#endif
 -  }
 -
 -  /* [12.12.7] The size of an event source is printed.*/
 -  test_set_step(7);
 -  {
 -#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
 -    test_print("--- EventS: ");
 -    test_printn(sizeof(event_source_t));
 -    test_println(" bytes");
 -#endif
 -  }
 -
 -  /* [12.12.8] The size of an event listener is printed.*/
 -  test_set_step(8);
 -  {
 -#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
 -    test_print("--- EventL: ");
 -    test_printn(sizeof(event_listener_t));
 -    test_println(" bytes");
 -#endif
 -  }
 -
 -  /* [12.12.9] The size of a mailbox is printed.*/
 -  test_set_step(9);
 -  {
 -#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
 -    test_print("--- MailB.: ");
 -    test_printn(sizeof(mailbox_t));
 -    test_println(" bytes");
 -#endif
 +    for (i = 0; i < 4; i++)
 +      test_assert(chPoolAlloc(&mp1) != NULL, "pool list empty");
 +    test_assert(chPoolAlloc(&mp1) == NULL, "pool list not empty");
    }
  }
 -static const testcase_t test_012_012 = {
 -  "RAM Footprint",
 -  NULL,
 +static const testcase_t test_012_002 = {
 +  "Threads creation from Memory Pool",
 +  test_012_002_setup,
    NULL,
 -  test_012_012_execute
 +  test_012_002_execute
  };
 +#endif /* CH_CFG_USE_MEMPOOLS */
  /****************************************************************************
   * Exported data.
   ****************************************************************************/
  /**
 - * @brief   Benchmarks.
 + * @brief   Dynamic threads.
   */
  const testcase_t * const test_sequence_012[] = {
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
    &test_012_001,
  #endif
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
    &test_012_002,
  #endif
 -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 -  &test_012_003,
 -#endif
 -  &test_012_004,
 -  &test_012_005,
 -  &test_012_006,
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 -  &test_012_007,
 -#endif
 -  &test_012_008,
 -  &test_012_009,
 -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 -  &test_012_010,
 -#endif
 -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 -  &test_012_011,
 -#endif
 -  &test_012_012,
    NULL
  };
 +
 +#endif /* CH_CFG_USE_DYNAMIC */
 diff --git a/test/rt/source/test/test_sequence_013.c b/test/rt/source/test/test_sequence_013.c new file mode 100644 index 000000000..126f94ad3 --- /dev/null +++ b/test/rt/source/test/test_sequence_013.c @@ -0,0 +1,1031 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
 +
 +    Licensed under the Apache License, Version 2.0 (the "License");
 +    you may not use this file except in compliance with the License.
 +    You may obtain a copy of the License at
 +
 +        http://www.apache.org/licenses/LICENSE-2.0
 +
 +    Unless required by applicable law or agreed to in writing, software
 +    distributed under the License is distributed on an "AS IS" BASIS,
 +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +    See the License for the specific language governing permissions and
 +    limitations under the License.
 +*/
 +
 +#include "hal.h"
 +#include "ch_test.h"
 +#include "test_root.h"
 +
 +/**
 + * @file    test_sequence_013.c
 + * @brief   Test Sequence 013 code.
 + *
 + * @page test_sequence_013 [13] Benchmarks
 + *
 + * File: @ref test_sequence_013.c
 + *
 + * <h2>Description</h2>
 + * This module implements a series of system benchmarks. The benchmarks
 + * are useful as a stress test and as a reference when comparing
 + * ChibiOS/RT with similar systems.<br> Objective of the test sequence
 + * is to provide a performance index for the most critical system
 + * subsystems. The performance numbers allow to discover performance
 + * regressions between successive ChibiOS/RT releases.
 + *
 + * <h2>Test Cases</h2>
 + * - @subpage test_013_001
 + * - @subpage test_013_002
 + * - @subpage test_013_003
 + * - @subpage test_013_004
 + * - @subpage test_013_005
 + * - @subpage test_013_006
 + * - @subpage test_013_007
 + * - @subpage test_013_008
 + * - @subpage test_013_009
 + * - @subpage test_013_010
 + * - @subpage test_013_011
 + * - @subpage test_013_012
 + * .
 + */
 +
 +/****************************************************************************
 + * Shared code.
 + ****************************************************************************/
 +
 +#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
 +static semaphore_t sem1;
 +#endif
 +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
 +static mutex_t mtx1;
 +#endif
 +
 +static void tmo(void *param) {(void)param;}
 +
 +#if CH_CFG_USE_MESSAGES
 +static THD_FUNCTION(bmk_thread1, p) {
 +  thread_t *tp;
 +  msg_t msg;
 +
 +  (void)p;
 +  do {
 +    tp = chMsgWait();
 +    msg = chMsgGet(tp);
 +    chMsgRelease(tp, msg);
 +  } while (msg);
 +}
 +
 +NOINLINE static unsigned int msg_loop_test(thread_t *tp) {
 +  systime_t start, end;
 +
 +  uint32_t n = 0;
 +  start = test_wait_tick();
 +  end = start + MS2ST(1000);
 +  do {
 +    (void)chMsgSend(tp, 1);
 +    n++;
 +#if defined(SIMULATOR)
 +    _sim_check_for_interrupts();
 +#endif
 +  } while (chVTIsSystemTimeWithinX(start, end));
 +  (void)chMsgSend(tp, 0);
 +  return n;
 +}
 +#endif
 +
 +static THD_FUNCTION(bmk_thread3, p) {
 +
 +  chThdExit((msg_t)p);
 +}
 +
 +static THD_FUNCTION(bmk_thread4, p) {
 +  msg_t msg;
 +  thread_t *self = chThdGetSelfX();
 +
 +  (void)p;
 +  chSysLock();
 +  do {
 +    chSchGoSleepS(CH_STATE_SUSPENDED);
 +    msg = self->u.rdymsg;
 +  } while (msg == MSG_OK);
 +  chSysUnlock();
 +}
 +
 +#if CH_CFG_USE_SEMAPHORES
 +static THD_FUNCTION(bmk_thread7, p) {
 +
 +  (void)p;
 +  while (!chThdShouldTerminateX())
 +    chSemWait(&sem1);
 +}
 +#endif
 +
 +static THD_FUNCTION(bmk_thread8, p) {
 +
 +  do {
 +    chThdYield();
 +    chThdYield();
 +    chThdYield();
 +    chThdYield();
 +    (*(uint32_t *)p) += 4;
 +#if defined(SIMULATOR)
 +    _sim_check_for_interrupts();
 +#endif
 +  } while(!chThdShouldTerminateX());
 +}
 +
 +/****************************************************************************
 + * Test cases.
 + ****************************************************************************/
 +
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +/**
 + * @page test_013_001 [13.1] Messages performance #1
 + *
 + * <h2>Description</h2>
 + * A message server thread is created with a lower priority than the
 + * client thread, the messages throughput per second is measured and
 + * the result printed on the output log.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_MESSAGES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [13.1.1] The messenger thread is started at a lower priority than
 + *   the current thread.
 + * - [13.1.2] The number of messages exchanged is counted in a one
 + *   second time window.
 + * - [13.1.3] Score is printed.
 + * .
 + */
 +
 +static void test_013_001_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.1.1] The messenger thread is started at a lower priority than
 +     the current thread.*/
 +  test_set_step(1);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread1, NULL);
 +  }
 +
 +  /* [13.1.2] The number of messages exchanged is counted in a one
 +     second time window.*/
 +  test_set_step(2);
 +  {
 +    n = msg_loop_test(threads[0]);
 +    test_wait_threads();
 +  }
 +
 +  /* [13.1.3] Score is printed.*/
 +  test_set_step(3);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_print(" msgs/S, ");
 +    test_printn(n << 1);
 +    test_println(" ctxswc/S");
 +  }
 +}
 +
 +static const testcase_t test_013_001 = {
 +  "Messages performance #1",
 +  NULL,
 +  NULL,
 +  test_013_001_execute
 +};
 +#endif /* CH_CFG_USE_MESSAGES */
 +
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +/**
 + * @page test_013_002 [13.2] Messages performance #2
 + *
 + * <h2>Description</h2>
 + * A message server thread is created with an higher priority than the
 + * client thread, the messages throughput per second is measured and
 + * the result printed on the output log.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_MESSAGES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [13.2.1] The messenger thread is started at an higher priority
 + *   than the current thread.
 + * - [13.2.2] The number of messages exchanged is counted in a one
 + *   second time window.
 + * - [13.2.3] Score is printed.
 + * .
 + */
 +
 +static void test_013_002_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.2.1] The messenger thread is started at an higher priority
 +     than the current thread.*/
 +  test_set_step(1);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL);
 +  }
 +
 +  /* [13.2.2] The number of messages exchanged is counted in a one
 +     second time window.*/
 +  test_set_step(2);
 +  {
 +    n = msg_loop_test(threads[0]);
 +    test_wait_threads();
 +  }
 +
 +  /* [13.2.3] Score is printed.*/
 +  test_set_step(3);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_print(" msgs/S, ");
 +    test_printn(n << 1);
 +    test_println(" ctxswc/S");
 +  }
 +}
 +
 +static const testcase_t test_013_002 = {
 +  "Messages performance #2",
 +  NULL,
 +  NULL,
 +  test_013_002_execute
 +};
 +#endif /* CH_CFG_USE_MESSAGES */
 +
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +/**
 + * @page test_013_003 [13.3] Messages performance #3
 + *
 + * <h2>Description</h2>
 + * A message server thread is created with an higher priority than the
 + * client thread, four lower priority threads crowd the ready list, the
 + * messages throughput per second is measured while the ready list and
 + * the result printed on the output log.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_MESSAGES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [13.3.1] The messenger thread is started at an higher priority
 + *   than the current thread.
 + * - [13.3.2] Four threads are started at a lower priority than the
 + *   current thread.
 + * - [13.3.3] The number of messages exchanged is counted in a one
 + *   second time window.
 + * - [13.3.4] Score is printed.
 + * .
 + */
 +
 +static void test_013_003_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.3.1] The messenger thread is started at an higher priority
 +     than the current thread.*/
 +  test_set_step(1);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL);
 +  }
 +
 +  /* [13.3.2] Four threads are started at a lower priority than the
 +     current thread.*/
 +  test_set_step(2);
 +  {
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, bmk_thread3, NULL);
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, bmk_thread3, NULL);
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-4, bmk_thread3, NULL);
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-5, bmk_thread3, NULL);
 +  }
 +
 +  /* [13.3.3] The number of messages exchanged is counted in a one
 +     second time window.*/
 +  test_set_step(3);
 +  {
 +    n = msg_loop_test(threads[0]);
 +    test_wait_threads();
 +  }
 +
 +  /* [13.3.4] Score is printed.*/
 +  test_set_step(4);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_print(" msgs/S, ");
 +    test_printn(n << 1);
 +    test_println(" ctxswc/S");
 +  }
 +}
 +
 +static const testcase_t test_013_003 = {
 +  "Messages performance #3",
 +  NULL,
 +  NULL,
 +  test_013_003_execute
 +};
 +#endif /* CH_CFG_USE_MESSAGES */
 +
 +/**
 + * @page test_013_004 [13.4] Context Switch performance
 + *
 + * <h2>Description</h2>
 + * A thread is created that just performs a @p chSchGoSleepS() into a
 + * loop, the thread is awakened as fast is possible by the tester
 + * thread.<br> The Context Switch performance is calculated by
 + * measuring the number of iterations after a second of continuous
 + * operations.
 + *
 + * <h2>Test Steps</h2>
 + * - [13.4.1] Starting the target thread at an higher priority level.
 + * - [13.4.2] Waking up the thread as fast as possible in a one second
 + *   time window.
 + * - [13.4.3] Stopping the target thread.
 + * - [13.4.4] Score is printed.
 + * .
 + */
 +
 +static void test_013_004_execute(void) {
 +  thread_t *tp;
 +  uint32_t n;
 +
 +  /* [13.4.1] Starting the target thread at an higher priority level.*/
 +  test_set_step(1);
 +  {
 +    tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1,
 +                                        bmk_thread4, NULL);
 +  }
 +
 +  /* [13.4.2] Waking up the thread as fast as possible in a one second
 +     time window.*/
 +  test_set_step(2);
 +  {
 +    systime_t start, end;
 +
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +      chSysLock();
 +      chSchWakeupS(tp, MSG_OK);
 +      chSchWakeupS(tp, MSG_OK);
 +      chSchWakeupS(tp, MSG_OK);
 +      chSchWakeupS(tp, MSG_OK);
 +      chSysUnlock();
 +      n += 4;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.4.3] Stopping the target thread.*/
 +  test_set_step(3);
 +  {
 +    chSysLock();
 +    chSchWakeupS(tp, MSG_TIMEOUT);
 +    chSysUnlock();
 +    test_wait_threads();
 +  }
 +
 +  /* [13.4.4] Score is printed.*/
 +  test_set_step(4);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n * 2);
 +    test_println(" ctxswc/S");
 +  }
 +}
 +
 +static const testcase_t test_013_004 = {
 +  "Context Switch performance",
 +  NULL,
 +  NULL,
 +  test_013_004_execute
 +};
 +
 +/**
 + * @page test_013_005 [13.5] Threads performance, full cycle
 + *
 + * <h2>Description</h2>
 + * Threads are continuously created and terminated into a loop. A full
 + * chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is
 + * performed in each iteration.<br> The performance is calculated by
 + * measuring the number of iterations after a second of continuous
 + * operations.
 + *
 + * <h2>Test Steps</h2>
 + * - [13.5.1] A thread is created at a lower priority level and its
 + *   termination detected using @p chThdWait(). The operation is
 + *   repeated continuously in a one-second time window.
 + * - [13.5.2] Score is printed.
 + * .
 + */
 +
 +static void test_013_005_execute(void) {
 +  uint32_t n;
 +  tprio_t prio = chThdGetPriorityX() - 1;
 +  systime_t start, end;
 +
 +  /* [13.5.1] A thread is created at a lower priority level and its
 +     termination detected using @p chThdWait(). The operation is
 +     repeated continuously in a one-second time window.*/
 +  test_set_step(1);
 +  {
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +      chThdWait(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL));
 +      n++;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.5.2] Score is printed.*/
 +  test_set_step(2);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_println(" threads/S");
 +  }
 +}
 +
 +static const testcase_t test_013_005 = {
 +  "Threads performance, full cycle",
 +  NULL,
 +  NULL,
 +  test_013_005_execute
 +};
 +
 +/**
 + * @page test_013_006 [13.6] Threads performance, create/exit only
 + *
 + * <h2>Description</h2>
 + * Threads are continuously created and terminated into a loop. A
 + * partial @p chThdCreateStatic() / @p chThdExit() cycle is performed
 + * in each iteration, the @p chThdWait() is not necessary because the
 + * thread is created at an higher priority so there is no need to wait
 + * for it to terminate.<br> The performance is calculated by measuring
 + * the number of iterations after a second of continuous operations.
 + *
 + * <h2>Test Steps</h2>
 + * - [13.6.1] A thread is created at an higher priority level and let
 + *   terminate immediately. The operation is repeated continuously in a
 + *   one-second time window.
 + * - [13.6.2] Score is printed.
 + * .
 + */
 +
 +static void test_013_006_execute(void) {
 +  uint32_t n;
 +  tprio_t prio = chThdGetPriorityX() + 1;
 +  systime_t start, end;
 +
 +  /* [13.6.1] A thread is created at an higher priority level and let
 +     terminate immediately. The operation is repeated continuously in a
 +     one-second time window.*/
 +  test_set_step(1);
 +  {
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +#if CH_CFG_USE_REGISTRY
 +      chThdRelease(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL));
 +#else
 +      chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL);
 +#endif
 +      n++;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.6.2] Score is printed.*/
 +  test_set_step(2);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_println(" threads/S");
 +  }
 +}
 +
 +static const testcase_t test_013_006 = {
 +  "Threads performance, create/exit only",
 +  NULL,
 +  NULL,
 +  test_013_006_execute
 +};
 +
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +/**
 + * @page test_013_007 [13.7] Mass reschedule performance
 + *
 + * <h2>Description</h2>
 + * Five threads are created and atomically rescheduled by resetting the
 + * semaphore where they are waiting on. The operation is performed into
 + * a continuous loop.<br> The performance is calculated by measuring
 + * the number of iterations after a second of continuous operations.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [13.7.1] Five threads are created at higher priority that
 + *   immediately enqueue on a semaphore.
 + * - [13.7.2] The semaphore is reset waking up the five threads. The
 + *   operation is repeated continuously in a one-second time window.
 + * - [13.7.3] The five threads are terminated.
 + * - [13.7.4] The score is printed.
 + * .
 + */
 +
 +static void test_013_007_setup(void) {
 +  chSemObjectInit(&sem1, 0);
 +}
 +
 +static void test_013_007_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.7.1] Five threads are created at higher priority that
 +     immediately enqueue on a semaphore.*/
 +  test_set_step(1);
 +  {
 +    threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, bmk_thread7, NULL);
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, bmk_thread7, NULL);
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, bmk_thread7, NULL);
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, bmk_thread7, NULL);
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, bmk_thread7, NULL);
 +  }
 +
 +  /* [13.7.2] The semaphore is reset waking up the five threads. The
 +     operation is repeated continuously in a one-second time window.*/
 +  test_set_step(2);
 +  {
 +    systime_t start, end;
 +
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +      chSemReset(&sem1, 0);
 +      n++;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.7.3] The five threads are terminated.*/
 +  test_set_step(3);
 +  {
 +    test_terminate_threads();
 +    chSemReset(&sem1, 0);
 +    test_wait_threads();
 +  }
 +
 +  /* [13.7.4] The score is printed.*/
 +  test_set_step(4);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_print(" reschedules/S, ");
 +    test_printn(n * 6);
 +    test_println(" ctxswc/S");
 +  }
 +}
 +
 +static const testcase_t test_013_007 = {
 +  "Mass reschedule performance",
 +  test_013_007_setup,
 +  NULL,
 +  test_013_007_execute
 +};
 +#endif /* CH_CFG_USE_SEMAPHORES */
 +
 +/**
 + * @page test_013_008 [13.8] Round-Robin voluntary reschedule
 + *
 + * <h2>Description</h2>
 + * Five threads are created at equal priority, each thread just
 + * increases a variable and yields.<br> The performance is calculated
 + * by measuring the number of iterations after a second of continuous
 + * operations.
 + *
 + * <h2>Test Steps</h2>
 + * - [13.8.1] The five threads are created at lower priority. The
 + *   threds have equal priority and start calling @p chThdYield()
 + *   continuously.
 + * - [13.8.2] Waiting one second then terminating the 5 threads.
 + * - [13.8.3] The score is printed.
 + * .
 + */
 +
 +static void test_013_008_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.8.1] The five threads are created at lower priority. The
 +     threds have equal priority and start calling @p chThdYield()
 +     continuously.*/
 +  test_set_step(1);
 +  {
 +    n = 0;
 +    test_wait_tick();threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 +
 +    threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 +    threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 +    threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 +    threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
 +  }
 +
 +  /* [13.8.2] Waiting one second then terminating the 5 threads.*/
 +  test_set_step(2);
 +  {
 +    chThdSleepSeconds(1);
 +    test_terminate_threads();
 +    test_wait_threads();
 +  }
 +
 +  /* [13.8.3] The score is printed.*/
 +  test_set_step(3);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n);
 +    test_println(" ctxswc/S");
 +  }
 +}
 +
 +static const testcase_t test_013_008 = {
 +  "Round-Robin voluntary reschedule",
 +  NULL,
 +  NULL,
 +  test_013_008_execute
 +};
 +
 +/**
 + * @page test_013_009 [13.9] Virtual Timers set/reset performance
 + *
 + * <h2>Description</h2>
 + * A virtual timer is set and immediately reset into a continuous
 + * loop.<br> The performance is calculated by measuring the number of
 + * iterations after a second of continuous operations.
 + *
 + * <h2>Test Steps</h2>
 + * - [13.9.1] Two timers are set then reset without waiting for their
 + *   counter to elapse. The operation is repeated continuously in a
 + *   one-second time window.
 + * - [13.9.2] The score is printed.
 + * .
 + */
 +
 +static void test_013_009_execute(void) {
 +  static virtual_timer_t vt1, vt2;
 +  uint32_t n;
 +
 +  /* [13.9.1] Two timers are set then reset without waiting for their
 +     counter to elapse. The operation is repeated continuously in a
 +     one-second time window.*/
 +  test_set_step(1);
 +  {
 +    systime_t start, end;
 +
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +      chSysLock();
 +      chVTDoSetI(&vt1, 1, tmo, NULL);
 +      chVTDoSetI(&vt2, 10000, tmo, NULL);
 +      chVTDoResetI(&vt1);
 +      chVTDoResetI(&vt2);
 +      chSysUnlock();
 +      n++;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.9.2] The score is printed.*/
 +  test_set_step(2);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n * 2);
 +    test_println(" timers/S");
 +  }
 +}
 +
 +static const testcase_t test_013_009 = {
 +  "Virtual Timers set/reset performance",
 +  NULL,
 +  NULL,
 +  test_013_009_execute
 +};
 +
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +/**
 + * @page test_013_010 [13.10] Semaphores wait/signal performance
 + *
 + * <h2>Description</h2>
 + * A counting semaphore is taken/released into a continuous loop, no
 + * Context Switch happens because the counter is always non
 + * negative.<br> The performance is calculated by measuring the number
 + * of iterations after a second of continuous operations.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_SEMAPHORES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [13.10.1] A semaphore is teken and released. The operation is
 + *   repeated continuously in a one-second time window.
 + * - [13.10.2] The score is printed.
 + * .
 + */
 +
 +static void test_013_010_setup(void) {
 +  chSemObjectInit(&sem1, 1);
 +}
 +
 +static void test_013_010_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.10.1] A semaphore is teken and released. The operation is
 +     repeated continuously in a one-second time window.*/
 +  test_set_step(1);
 +  {
 +    systime_t start, end;
 +
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +      chSemWait(&sem1);
 +      chSemSignal(&sem1);
 +      chSemWait(&sem1);
 +      chSemSignal(&sem1);
 +      chSemWait(&sem1);
 +      chSemSignal(&sem1);
 +      chSemWait(&sem1);
 +      chSemSignal(&sem1);
 +      n++;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.10.2] The score is printed.*/
 +  test_set_step(2);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n * 4);
 +    test_println(" wait+signal/S");
 +  }
 +}
 +
 +static const testcase_t test_013_010 = {
 +  "Semaphores wait/signal performance",
 +  test_013_010_setup,
 +  NULL,
 +  test_013_010_execute
 +};
 +#endif /* CH_CFG_USE_SEMAPHORES */
 +
 +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +/**
 + * @page test_013_011 [13.11] Mutexes lock/unlock performance
 + *
 + * <h2>Description</h2>
 + * A mutex is locked/unlocked into a continuous loop, no Context Switch
 + * happens because there are no other threads asking for the mutex.<br>
 + * The performance is calculated by measuring the number of iterations
 + * after a second of continuous operations.
 + *
 + * <h2>Conditions</h2>
 + * This test is only executed if the following preprocessor condition
 + * evaluates to true:
 + * - CH_CFG_USE_MUTEXES
 + * .
 + *
 + * <h2>Test Steps</h2>
 + * - [13.11.1] A mutex is locked and unlocked. The operation is
 + *   repeated continuously in a one-second time window.
 + * - [13.11.2] The score is printed.
 + * .
 + */
 +
 +static void test_013_011_setup(void) {
 +  chMtxObjectInit(&mtx1);
 +}
 +
 +static void test_013_011_execute(void) {
 +  uint32_t n;
 +
 +  /* [13.11.1] A mutex is locked and unlocked. The operation is
 +     repeated continuously in a one-second time window.*/
 +  test_set_step(1);
 +  {
 +    systime_t start, end;
 +
 +    n = 0;
 +    start = test_wait_tick();
 +    end = start + MS2ST(1000);
 +    do {
 +      chMtxLock(&mtx1);
 +      chMtxUnlock(&mtx1);
 +      chMtxLock(&mtx1);
 +      chMtxUnlock(&mtx1);
 +      chMtxLock(&mtx1);
 +      chMtxUnlock(&mtx1);
 +      chMtxLock(&mtx1);
 +      chMtxUnlock(&mtx1);
 +      n++;
 +#if defined(SIMULATOR)
 +      _sim_check_for_interrupts();
 +#endif
 +    } while (chVTIsSystemTimeWithinX(start, end));
 +  }
 +
 +  /* [13.11.2] The score is printed.*/
 +  test_set_step(2);
 +  {
 +    test_print("--- Score : ");
 +    test_printn(n * 4);
 +    test_println(" lock+unlock/S");
 +  }
 +}
 +
 +static const testcase_t test_013_011 = {
 +  "Mutexes lock/unlock performance",
 +  test_013_011_setup,
 +  NULL,
 +  test_013_011_execute
 +};
 +#endif /* CH_CFG_USE_MUTEXES */
 +
 +/**
 + * @page test_013_012 [13.12] RAM Footprint
 + *
 + * <h2>Description</h2>
 + * The memory size of the various kernel objects is printed.
 + *
 + * <h2>Test Steps</h2>
 + * - [13.12.1] The size of the system area is printed.
 + * - [13.12.2] The size of a thread structure is printed.
 + * - [13.12.3] The size of a virtual timer structure is printed.
 + * - [13.12.4] The size of a semaphore structure is printed.
 + * - [13.12.5] The size of a mutex is printed.
 + * - [13.12.6] The size of a condition variable is printed.
 + * - [13.12.7] The size of an event source is printed.
 + * - [13.12.8] The size of an event listener is printed.
 + * - [13.12.9] The size of a mailbox is printed.
 + * .
 + */
 +
 +static void test_013_012_execute(void) {
 +
 +  /* [13.12.1] The size of the system area is printed.*/
 +  test_set_step(1);
 +  {
 +    test_print("--- System: ");
 +    test_printn(sizeof(ch_system_t));
 +    test_println(" bytes");
 +  }
 +
 +  /* [13.12.2] The size of a thread structure is printed.*/
 +  test_set_step(2);
 +  {
 +    test_print("--- Thread: ");
 +    test_printn(sizeof(thread_t));
 +    test_println(" bytes");
 +  }
 +
 +  /* [13.12.3] The size of a virtual timer structure is printed.*/
 +  test_set_step(3);
 +  {
 +    test_print("--- Timer : ");
 +    test_printn(sizeof(virtual_timer_t));
 +    test_println(" bytes");
 +  }
 +
 +  /* [13.12.4] The size of a semaphore structure is printed.*/
 +  test_set_step(4);
 +  {
 +#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
 +    test_print("--- Semaph: ");
 +    test_printn(sizeof(semaphore_t));
 +    test_println(" bytes");
 +#endif
 +  }
 +
 +  /* [13.12.5] The size of a mutex is printed.*/
 +  test_set_step(5);
 +  {
 +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
 +    test_print("--- Mutex : ");
 +    test_printn(sizeof(mutex_t));
 +    test_println(" bytes");
 +#endif
 +  }
 +
 +  /* [13.12.6] The size of a condition variable is printed.*/
 +  test_set_step(6);
 +  {
 +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
 +    test_print("--- CondV.: ");
 +    test_printn(sizeof(condition_variable_t));
 +    test_println(" bytes");
 +#endif
 +  }
 +
 +  /* [13.12.7] The size of an event source is printed.*/
 +  test_set_step(7);
 +  {
 +#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
 +    test_print("--- EventS: ");
 +    test_printn(sizeof(event_source_t));
 +    test_println(" bytes");
 +#endif
 +  }
 +
 +  /* [13.12.8] The size of an event listener is printed.*/
 +  test_set_step(8);
 +  {
 +#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
 +    test_print("--- EventL: ");
 +    test_printn(sizeof(event_listener_t));
 +    test_println(" bytes");
 +#endif
 +  }
 +
 +  /* [13.12.9] The size of a mailbox is printed.*/
 +  test_set_step(9);
 +  {
 +#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
 +    test_print("--- MailB.: ");
 +    test_printn(sizeof(mailbox_t));
 +    test_println(" bytes");
 +#endif
 +  }
 +}
 +
 +static const testcase_t test_013_012 = {
 +  "RAM Footprint",
 +  NULL,
 +  NULL,
 +  test_013_012_execute
 +};
 +
 +/****************************************************************************
 + * Exported data.
 + ****************************************************************************/
 +
 +/**
 + * @brief   Benchmarks.
 + */
 +const testcase_t * const test_sequence_013[] = {
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +  &test_013_001,
 +#endif
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +  &test_013_002,
 +#endif
 +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
 +  &test_013_003,
 +#endif
 +  &test_013_004,
 +  &test_013_005,
 +  &test_013_006,
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +  &test_013_007,
 +#endif
 +  &test_013_008,
 +  &test_013_009,
 +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
 +  &test_013_010,
 +#endif
 +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
 +  &test_013_011,
 +#endif
 +  &test_013_012,
 +  NULL
 +};
 diff --git a/test/rt/source/test/test_sequence_013.h b/test/rt/source/test/test_sequence_013.h new file mode 100644 index 000000000..acf57a0b9 --- /dev/null +++ b/test/rt/source/test/test_sequence_013.h @@ -0,0 +1,27 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
 +
 +    Licensed under the Apache License, Version 2.0 (the "License");
 +    you may not use this file except in compliance with the License.
 +    You may obtain a copy of the License at
 +
 +        http://www.apache.org/licenses/LICENSE-2.0
 +
 +    Unless required by applicable law or agreed to in writing, software
 +    distributed under the License is distributed on an "AS IS" BASIS,
 +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +    See the License for the specific language governing permissions and
 +    limitations under the License.
 +*/
 +
 +/**
 + * @file    test_sequence_013.h
 + * @brief   Test Sequence 013 header.
 + */
 +
 +#ifndef TEST_SEQUENCE_013_H
 +#define TEST_SEQUENCE_013_H
 +
 +extern const testcase_t * const test_sequence_013[];
 +
 +#endif /* TEST_SEQUENCE_013_H */
 diff --git a/test/rt/test.mk b/test/rt/test.mk index f6495c2ad..e9c74676a 100644 --- a/test/rt/test.mk +++ b/test/rt/test.mk @@ -12,7 +12,8 @@ TESTSRC = ${CHIBIOS}/test/lib/ch_test.c \            ${CHIBIOS}/test/rt/source/test/test_sequence_009.c \
            ${CHIBIOS}/test/rt/source/test/test_sequence_010.c \
            ${CHIBIOS}/test/rt/source/test/test_sequence_011.c \
 -          ${CHIBIOS}/test/rt/source/test/test_sequence_012.c
 +          ${CHIBIOS}/test/rt/source/test/test_sequence_012.c \
 +          ${CHIBIOS}/test/rt/source/test/test_sequence_013.c
  # Required include directories
  TESTINC = ${CHIBIOS}/test/lib \
  | 
