Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:46

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup sptests
0007  *
0008  * @brief Test for timer server with blocking calls.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2015 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <tmacros.h>
0041 
0042 const char rtems_test_name[] = "SP 68";
0043 
0044 /* forward declarations to avoid warnings */
0045 rtems_task Init(rtems_task_argument argument);
0046 
0047 #define TIMER_COUNT 6
0048 
0049 #define OBTAIN 0
0050 #define RELEASE 1
0051 #define INTERRUPT 2
0052 #define DELAYED 3
0053 #define SERVER_TRIGGERED 4
0054 #define INTERRUPT_TRIGGERED 5
0055 
0056 #define T0 0
0057 #define T1 1
0058 #define T2 2
0059 #define T3 3
0060 #define T4 4
0061 #define T5 5
0062 #define T6 6
0063 
0064 static volatile bool obtain_try;
0065 static volatile bool obtain_done;
0066 static volatile bool release_happened;
0067 static volatile bool interrupt_happened;
0068 static volatile bool delayed_happened;
0069 static volatile bool server_triggered_happened;
0070 static volatile bool interrupt_triggered_happened;
0071 
0072 static rtems_id timer [TIMER_COUNT];
0073 
0074 static rtems_id semaphore;
0075 static rtems_id mutex;
0076 static rtems_id message_queue;
0077 static rtems_id region;
0078 static rtems_id barrier;
0079 
0080 static void *region_item;
0081 
0082 static rtems_interval start;
0083 
0084 static rtems_id timer_server_id;
0085 
0086 static volatile enum resource_type {
0087   SEMAPHORE = 0,
0088   MUTEX,
0089   MESSAGE_QUEUE,
0090   REGION,
0091   EVENT,
0092   BARRIER,
0093   TASK_WAKE_AFTER
0094 } resource_type;
0095 
0096 static const char *const resource_type_desc [] = {
0097   "SEMAPHORE",
0098   "MUTEX",
0099   "MESSAGE QUEUE",
0100   "REGION",
0101   "EVENT",
0102   "BARRIER",
0103   "TASK WAKE AFTER"
0104 };
0105 
0106 static void assert_time(rtems_interval expected)
0107 {
0108   rtems_test_assert((rtems_clock_get_ticks_since_boot() - start) == expected);
0109 }
0110 
0111 static void obtain_callback(rtems_id timer_id, void *arg)
0112 {
0113   rtems_status_code sc = RTEMS_SUCCESSFUL;
0114   char buf [1];
0115   size_t size = sizeof(buf);
0116   void *new_region_item = NULL;
0117   rtems_event_set events = 0;
0118 
0119   assert_time(T1);
0120 
0121   rtems_test_assert(
0122     !release_happened
0123       && !interrupt_happened
0124       && !delayed_happened
0125       && !interrupt_triggered_happened
0126       && !server_triggered_happened
0127   );
0128 
0129   obtain_try = true;
0130 
0131   switch (resource_type) {
0132     case SEMAPHORE:
0133       sc = rtems_semaphore_obtain(semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0134       break;
0135     case MUTEX:
0136       sc = rtems_semaphore_obtain(mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0137       break;
0138     case MESSAGE_QUEUE:
0139       sc = rtems_message_queue_receive(
0140         message_queue, buf, &size, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0141       break;
0142     case REGION:
0143       sc = rtems_region_get_segment(
0144         region, 1, RTEMS_WAIT, RTEMS_NO_TIMEOUT, &new_region_item);
0145       break;
0146     case EVENT:
0147       timer_server_id = rtems_task_self();
0148       sc = rtems_event_receive(
0149         RTEMS_EVENT_0, RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
0150       break;
0151     case BARRIER:
0152       sc = rtems_barrier_wait(barrier, RTEMS_NO_TIMEOUT);
0153       break;
0154     case TASK_WAKE_AFTER:
0155       sc = rtems_task_wake_after(T4 - T1);
0156       break;
0157     default:
0158       rtems_test_assert(false);
0159       break;
0160   }
0161   directive_failed(sc, "obtain");
0162 
0163   obtain_done = true;
0164 }
0165 
0166 static void release_callback(rtems_id timer_id, void *arg)
0167 {
0168   rtems_status_code sc = RTEMS_SUCCESSFUL;
0169   char buf [1] = { 0 };
0170   size_t size = sizeof(buf);
0171   uint32_t released = 0;
0172 
0173   assert_time(T4);
0174 
0175   rtems_test_assert(
0176     obtain_try
0177       && interrupt_happened
0178       && !delayed_happened
0179       && !interrupt_triggered_happened
0180       && !server_triggered_happened
0181   );
0182 
0183   switch (resource_type) {
0184     case SEMAPHORE:
0185       sc = rtems_semaphore_release(semaphore);
0186       break;
0187     case MUTEX:
0188       sc = rtems_semaphore_release(mutex);
0189       break;
0190     case MESSAGE_QUEUE:
0191       sc = rtems_message_queue_send(message_queue, buf, size);
0192       break;
0193     case EVENT:
0194       sc = rtems_event_send(timer_server_id, RTEMS_EVENT_0);
0195       break;
0196     case BARRIER:
0197       sc = rtems_barrier_release(barrier, &released);
0198       break;
0199     case TASK_WAKE_AFTER:
0200       sc = RTEMS_SUCCESSFUL;
0201       break;
0202     default:
0203       rtems_test_assert(false);
0204       break;
0205   }
0206   directive_failed_with_level(sc, "release", 1);
0207 
0208   release_happened = true;
0209 }
0210 
0211 static void interrupt_triggered_callback(rtems_id timer_id, void *arg)
0212 {
0213   /*
0214    * This callback is scheduled to fire at T3, but is delayed due to the
0215    * blocked obtain callback.
0216    */
0217   assert_time(T4);
0218 
0219   rtems_test_assert(
0220     obtain_done
0221       && release_happened
0222       && interrupt_happened
0223       && !server_triggered_happened
0224   );
0225 
0226   interrupt_triggered_happened = true;
0227 }
0228 
0229 static void interrupt_callback(rtems_id timer_id, void *arg)
0230 {
0231   rtems_status_code sc = RTEMS_SUCCESSFUL;
0232 
0233   assert_time(T2);
0234 
0235   rtems_test_assert(
0236     obtain_try
0237       && !obtain_done
0238       && !release_happened
0239       && !delayed_happened
0240       && !interrupt_triggered_happened
0241       && !server_triggered_happened
0242   );
0243 
0244   sc = rtems_timer_server_fire_after(
0245     timer [INTERRUPT_TRIGGERED],
0246     T3 - T2,
0247     interrupt_triggered_callback,
0248     NULL
0249   );
0250   directive_failed_with_level(sc, "rtems_timer_server_fire_after", -1);
0251 
0252   interrupt_happened = true;
0253 }
0254 
0255 static void server_triggered_callback(rtems_id timer_id, void *arg)
0256 {
0257   assert_time(T5);
0258 
0259   rtems_test_assert(
0260     obtain_done
0261       && release_happened
0262       && interrupt_happened
0263       && delayed_happened
0264       && interrupt_triggered_happened
0265   );
0266 
0267   server_triggered_happened = true;
0268 }
0269 
0270 static void delayed_callback(rtems_id timer_id, void *arg)
0271 {
0272   rtems_status_code sc = RTEMS_SUCCESSFUL;
0273 
0274   assert_time(T4);
0275 
0276   rtems_test_assert(
0277     obtain_done
0278       && release_happened
0279       && interrupt_happened
0280       && !server_triggered_happened
0281   );
0282 
0283   sc = rtems_timer_server_fire_after(
0284     timer [SERVER_TRIGGERED],
0285     T5 - T4,
0286     server_triggered_callback,
0287     NULL
0288   );
0289   directive_failed(sc, "rtems_timer_server_fire_after");
0290 
0291   delayed_happened = true;
0292 }
0293 
0294 static void test_reset(void)
0295 {
0296   rtems_status_code sc = RTEMS_SUCCESSFUL;
0297 
0298   obtain_try = false;
0299   obtain_done = false;
0300   release_happened = false;
0301   interrupt_happened = false;
0302   delayed_happened = false;
0303   interrupt_triggered_happened = false;
0304   server_triggered_happened = false;
0305 
0306   /* Synchronize with tick */
0307   sc = rtems_task_wake_after(1);
0308   directive_failed(sc, "rtems_task_wake_after");
0309 
0310   start = rtems_clock_get_ticks_since_boot();
0311 }
0312 
0313 static void test_case(enum resource_type rt)
0314 {
0315   rtems_status_code sc = RTEMS_SUCCESSFUL;
0316 
0317   printf("test case: %s\n", resource_type_desc [rt]);
0318 
0319   resource_type = rt;
0320 
0321   test_reset();
0322 
0323   sc = rtems_timer_server_fire_after(
0324     timer [OBTAIN],
0325     T1 - T0,
0326     obtain_callback,
0327     NULL
0328   );
0329   directive_failed(sc, "rtems_timer_server_fire_after");
0330 
0331   sc = rtems_timer_fire_after(
0332     timer [INTERRUPT],
0333     T2 - T0,
0334     interrupt_callback,
0335     NULL
0336   );
0337   directive_failed(sc, "rtems_timer_fire_after");
0338 
0339   sc = rtems_timer_server_fire_after(
0340     timer [DELAYED],
0341     T3 - T0,
0342     delayed_callback,
0343     NULL
0344   );
0345   directive_failed(sc, "rtems_timer_server_fire_after");
0346 
0347   if (resource_type != REGION) {
0348     sc = rtems_timer_fire_after(
0349       timer [RELEASE],
0350       T4 - T0,
0351       release_callback,
0352       NULL
0353     );
0354     directive_failed(sc, "rtems_timer_fire_after");
0355 
0356     assert_time(T0);
0357 
0358     sc = rtems_task_wake_after(T6 - T0);
0359     directive_failed(sc, "task_wake_after");
0360   } else {
0361     sc = rtems_task_wake_after(T4 - T0);
0362     directive_failed(sc, "task_wake_after");
0363 
0364     assert_time(T4);
0365 
0366     rtems_test_assert(
0367       obtain_try
0368         && interrupt_happened
0369         && !delayed_happened
0370         && !interrupt_triggered_happened
0371         && !server_triggered_happened
0372     );
0373 
0374     sc = rtems_region_return_segment(region, region_item);
0375     directive_failed(sc, "rtems_region_return_segment");
0376 
0377     release_happened = true;
0378 
0379     sc = rtems_task_wake_after(T6 - T4);
0380     directive_failed(sc, "task_wake_after");
0381   }
0382 
0383   assert_time(T6);
0384 
0385   rtems_test_assert(
0386     obtain_done
0387       && interrupt_happened
0388       && release_happened
0389       && delayed_happened
0390       && interrupt_triggered_happened
0391       && server_triggered_happened
0392   );
0393 }
0394 
0395 rtems_task Init(rtems_task_argument argument)
0396 {
0397   rtems_status_code sc = RTEMS_SUCCESSFUL;
0398   char region_area [256];
0399   enum resource_type rt = SEMAPHORE;
0400   void *new_region_item = NULL;
0401   size_t i = 0;
0402 
0403   TEST_BEGIN();
0404 
0405   for (i = 0; i < TIMER_COUNT; ++i) {
0406     sc = rtems_timer_create(
0407       rtems_build_name('T', 'I', 'M', '0' + i),
0408       &timer [i]
0409     );
0410     directive_failed(sc, "rtems_timer_create");
0411   }
0412 
0413   sc = rtems_timer_initiate_server(
0414     RTEMS_MINIMUM_PRIORITY,
0415     RTEMS_MINIMUM_STACK_SIZE,
0416     RTEMS_DEFAULT_ATTRIBUTES
0417   );
0418   directive_failed(sc, "rtems_timer_initiate_server");
0419 
0420   sc = rtems_semaphore_create(
0421     rtems_build_name('S', 'E', 'M', 'A'),
0422     0,
0423     RTEMS_LOCAL | RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE,
0424     0,
0425     &semaphore
0426   );
0427   directive_failed(sc, "rtems_semaphore_create");
0428 
0429   sc = rtems_semaphore_create(
0430     rtems_build_name('M', 'U', 'T', 'X'),
0431     0,
0432     RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
0433     0,
0434     &mutex
0435   );
0436   directive_failed(sc, "rtems_semaphore_create");
0437 
0438   sc = rtems_message_queue_create(
0439     rtems_build_name('M', 'S', 'G', 'Q'),
0440     1,
0441     1,
0442     RTEMS_LOCAL | RTEMS_FIFO,
0443     &message_queue
0444   );
0445   directive_failed(sc, "rtems_message_queue_create");
0446 
0447   sc = rtems_region_create(
0448     rtems_build_name('R', 'E', 'G', 'I'),
0449     region_area,
0450     sizeof(region_area),
0451     1,
0452     RTEMS_LOCAL | RTEMS_FIFO,
0453     &region
0454   );
0455   directive_failed(sc, "rtems_region_create");
0456 
0457   do {
0458     region_item = new_region_item;
0459     sc = rtems_region_get_segment(
0460         region, 1, RTEMS_NO_WAIT, 0, &new_region_item);
0461   } while (sc == RTEMS_SUCCESSFUL);
0462 
0463   sc = rtems_barrier_create(
0464     rtems_build_name('B', 'A', 'R', 'R'),
0465     RTEMS_LOCAL | RTEMS_FIFO,
0466     2,
0467     &barrier
0468   );
0469   directive_failed(sc, "rtems_barrier_create");
0470 
0471   while (rt <= TASK_WAKE_AFTER) {
0472     test_case(rt);
0473     ++rt;
0474   }
0475 
0476   TEST_END();
0477 
0478   rtems_test_exit(0);
0479 }
0480 
0481 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0482 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0483 
0484 #define CONFIGURE_MAXIMUM_TASKS 2
0485 #define CONFIGURE_MAXIMUM_TIMERS TIMER_COUNT
0486 #define CONFIGURE_MAXIMUM_SEMAPHORES 2
0487 #define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 1
0488 #define CONFIGURE_MESSAGE_BUFFER_MEMORY \
0489   CONFIGURE_MESSAGE_BUFFERS_FOR_QUEUE(1, 1)
0490 #define CONFIGURE_MAXIMUM_REGIONS 1
0491 #define CONFIGURE_MAXIMUM_BARRIERS 1
0492 
0493 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0494 
0495 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0496 
0497 #define CONFIGURE_INIT
0498 
0499 #include <rtems/confdefs.h>