Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2015 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include "tmacros.h"
0033 
0034 #include <threads.h>
0035 
0036 #include <rtems/malloc.h>
0037 
0038 const char rtems_test_name[] = "SPSTDTHREADS 1";
0039 
0040 #define US_PER_TICK 10000
0041 
0042 #define EVENT_MTX_LOCK RTEMS_EVENT_0
0043 
0044 #define EVENT_MTX_UNLOCK RTEMS_EVENT_1
0045 
0046 #define EVENT_CND_WAIT RTEMS_EVENT_2
0047 
0048 #define EVENT_CND_TIMEDWAIT RTEMS_EVENT_3
0049 
0050 #define EVENT_TSS RTEMS_EVENT_4
0051 
0052 typedef struct {
0053   rtems_id high;
0054   rtems_id low;
0055   once_flag once_flag;
0056   mtx_t mtx;
0057   cnd_t cnd;
0058   tss_t tss;
0059   thrd_t thrd;
0060   int generation;
0061 } test_context;
0062 
0063 static test_context test_instance = {
0064   .once_flag = ONCE_FLAG_INIT
0065 };
0066 
0067 static void next_generation(test_context *ctx)
0068 {
0069   ++ctx->generation;
0070 }
0071 
0072 static void send_event(test_context *ctx, rtems_event_set events)
0073 {
0074   rtems_status_code sc;
0075 
0076   sc = rtems_event_send(ctx->high, events);
0077   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0078 }
0079 
0080 static void get_abs_timeout(struct timespec *to)
0081 {
0082   int rv;
0083 
0084   rv = clock_gettime(CLOCK_REALTIME, to);
0085   rtems_test_assert(rv == 0);
0086 
0087   to->tv_nsec += 2 * US_PER_TICK * 1000;
0088   if (to->tv_nsec >= 1000000000) {
0089     ++to->tv_sec;
0090     to->tv_nsec -= 1000000000;
0091   }
0092 }
0093 
0094 static void test_init(test_context *ctx)
0095 {
0096   int status;
0097 
0098   status = mtx_init(&ctx->mtx, mtx_plain);
0099   rtems_test_assert(status == thrd_success);
0100 
0101   status = cnd_init(&ctx->cnd);
0102   rtems_test_assert(status == thrd_success);
0103 }
0104 
0105 static void test_destroy(test_context *ctx)
0106 {
0107   mtx_destroy(&ctx->mtx);
0108   cnd_destroy(&ctx->cnd);
0109 }
0110 
0111 static void once_func(void)
0112 {
0113   test_context *ctx = &test_instance;
0114 
0115   next_generation(ctx);
0116 }
0117 
0118 static void test_once(test_context *ctx)
0119 {
0120   int gen = ctx->generation;
0121 
0122   call_once(&ctx->once_flag, once_func);
0123   rtems_test_assert(ctx->generation == gen + 1);
0124 
0125   call_once(&ctx->once_flag, once_func);
0126   rtems_test_assert(ctx->generation == gen + 1);
0127 }
0128 
0129 static void test_mtx(test_context *ctx)
0130 {
0131   mtx_t *mtx = &ctx->mtx;
0132   int gen = ctx->generation;
0133   struct timespec to;
0134   int status;
0135 
0136   status = mtx_trylock(mtx);
0137   rtems_test_assert(status == thrd_success);
0138 
0139   status = mtx_lock(mtx);
0140   rtems_test_assert(status == thrd_success);
0141 
0142   get_abs_timeout(&to);
0143   status = mtx_timedlock(mtx, &to);
0144   rtems_test_assert(status == thrd_success);
0145 
0146   status = mtx_unlock(mtx);
0147   rtems_test_assert(status == thrd_success);
0148 
0149   status = mtx_unlock(mtx);
0150   rtems_test_assert(status == thrd_success);
0151 
0152   status = mtx_unlock(mtx);
0153   rtems_test_assert(status == thrd_success);
0154 
0155   send_event(ctx, EVENT_MTX_LOCK);
0156   rtems_test_assert(ctx->generation == gen + 1);
0157 
0158   status = mtx_trylock(mtx);
0159   rtems_test_assert(status == thrd_busy);
0160 
0161   memset(&to, 0xff, sizeof(to));
0162   status = mtx_timedlock(mtx, &to);
0163   rtems_test_assert(status == thrd_error);
0164 
0165   get_abs_timeout(&to);
0166   status = mtx_timedlock(mtx, &to);
0167   rtems_test_assert(status == thrd_timedout);
0168 
0169   send_event(ctx, EVENT_MTX_UNLOCK);
0170   rtems_test_assert(ctx->generation == gen + 2);
0171 }
0172 
0173 static void test_cnd(test_context *ctx)
0174 {
0175   cnd_t *cnd = &ctx->cnd;
0176   mtx_t *mtx = &ctx->mtx;
0177   int gen = ctx->generation;
0178   struct timespec to;
0179   int status;
0180 
0181   send_event(ctx, EVENT_CND_WAIT);
0182   rtems_test_assert(ctx->generation == gen + 1);
0183 
0184   status = mtx_lock(mtx);
0185   rtems_test_assert(status == thrd_success);
0186 
0187   status = cnd_signal(cnd);
0188   rtems_test_assert(status == thrd_success);
0189 
0190   status = mtx_unlock(mtx);
0191   rtems_test_assert(status == thrd_success);
0192   rtems_test_assert(ctx->generation == gen + 2);
0193 
0194   send_event(ctx, EVENT_CND_WAIT);
0195   rtems_test_assert(ctx->generation == gen + 3);
0196 
0197   status = mtx_lock(mtx);
0198   rtems_test_assert(status == thrd_success);
0199 
0200   status = cnd_broadcast(cnd);
0201   rtems_test_assert(status == thrd_success);
0202 
0203   status = mtx_unlock(mtx);
0204   rtems_test_assert(status == thrd_success);
0205   rtems_test_assert(ctx->generation == gen + 4);
0206 
0207   status = mtx_lock(mtx);
0208   rtems_test_assert(status == thrd_success);
0209 
0210   memset(&to, 0xff, sizeof(to));
0211   status = cnd_timedwait(cnd, mtx, &to);
0212   rtems_test_assert(status == thrd_error);
0213 
0214   get_abs_timeout(&to);
0215   status = cnd_timedwait(cnd, mtx, &to);
0216   rtems_test_assert(status == thrd_timedout);
0217 
0218   status = mtx_unlock(mtx);
0219   rtems_test_assert(status == thrd_success);
0220 
0221   send_event(ctx, EVENT_CND_TIMEDWAIT);
0222   rtems_test_assert(ctx->generation == gen + 5);
0223 
0224   status = mtx_lock(mtx);
0225   rtems_test_assert(status == thrd_success);
0226 
0227   status = cnd_signal(cnd);
0228   rtems_test_assert(status == thrd_success);
0229 
0230   status = mtx_unlock(mtx);
0231   rtems_test_assert(status == thrd_success);
0232   rtems_test_assert(ctx->generation == gen + 6);
0233 }
0234 
0235 static int tss_val = TSS_DTOR_ITERATIONS;
0236 
0237 static void tss_dtor(void *val)
0238 {
0239   test_context *ctx = &test_instance;
0240 
0241   rtems_test_assert(val == &tss_val);
0242   next_generation(ctx);
0243 }
0244 
0245 static void test_tss(test_context *ctx)
0246 {
0247   tss_dtor_t dtor = tss_dtor;
0248   int gen = ctx->generation;
0249   int status;
0250 
0251   status = tss_create(&ctx->tss, dtor);
0252   rtems_test_assert(status == thrd_success);
0253 
0254   send_event(ctx, EVENT_TSS);
0255   rtems_test_assert(ctx->generation == gen + 1);
0256 
0257   tss_delete(ctx->tss);
0258 }
0259 
0260 static int thrd(void *arg)
0261 {
0262   thrd_exit(123);
0263 }
0264 
0265 static void test_thrd(test_context *ctx)
0266 {
0267   thrd_start_t thrd_start = thrd;
0268   int status;
0269   int exit_status;
0270   struct timespec duration;
0271   struct timespec remaining;
0272   void *greedy;
0273 
0274   rtems_test_assert(thrd_equal(rtems_task_self(), thrd_current()));
0275 
0276   thrd_yield();
0277 
0278   memset(&duration, 0, sizeof(duration));
0279   duration.tv_nsec = 1;
0280   thrd_sleep(&duration, &remaining);
0281   rtems_test_assert(remaining.tv_sec == 0);
0282   rtems_test_assert(remaining.tv_nsec == 0);
0283 
0284   greedy = rtems_heap_greedy_allocate(NULL, 0);
0285   status = thrd_create(&ctx->thrd, thrd_start, ctx);
0286   rtems_test_assert(status == thrd_nomem);
0287   rtems_heap_greedy_free(greedy);
0288 
0289   status = thrd_create(&ctx->thrd, thrd_start, ctx);
0290   rtems_test_assert(status == thrd_success);
0291 
0292   status = thrd_create(&ctx->thrd, thrd_start, ctx);
0293   rtems_test_assert(status == thrd_error);
0294 
0295   exit_status = 0;
0296   status = thrd_join(ctx->thrd, &exit_status);
0297   rtems_test_assert(status == thrd_success);
0298   rtems_test_assert(exit_status == 123);
0299 
0300   status = thrd_detach(thrd_current());
0301   rtems_test_assert(status == thrd_success);
0302 
0303   status = thrd_detach(11235);
0304   rtems_test_assert(status == thrd_error);
0305 }
0306 
0307 static void high_task(rtems_task_argument idx)
0308 {
0309   test_context *ctx = &test_instance;
0310 
0311   while (true) {
0312     rtems_event_set events;
0313     rtems_status_code sc;
0314     int status;
0315 
0316     sc = rtems_event_receive(
0317       RTEMS_ALL_EVENTS,
0318       RTEMS_EVENT_ANY | RTEMS_WAIT,
0319       RTEMS_NO_TIMEOUT,
0320       &events
0321     );
0322     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0323 
0324     if ((events & EVENT_MTX_LOCK) != 0) {
0325       status = mtx_lock(&ctx->mtx);
0326       rtems_test_assert(status == thrd_success);
0327       next_generation(ctx);
0328     }
0329 
0330     if ((events & EVENT_MTX_UNLOCK) != 0) {
0331       status = mtx_unlock(&ctx->mtx);
0332       rtems_test_assert(status == thrd_success);
0333       next_generation(ctx);
0334     }
0335 
0336     if ((events & EVENT_CND_WAIT) != 0) {
0337       status = mtx_lock(&ctx->mtx);
0338       rtems_test_assert(status == thrd_success);
0339       next_generation(ctx);
0340 
0341       status = cnd_wait(&ctx->cnd, &ctx->mtx);
0342       rtems_test_assert(status == thrd_success);
0343       next_generation(ctx);
0344 
0345       status = mtx_unlock(&ctx->mtx);
0346       rtems_test_assert(status == thrd_success);
0347     }
0348 
0349     if ((events & EVENT_CND_TIMEDWAIT) != 0) {
0350       struct timespec to;
0351 
0352       status = mtx_lock(&ctx->mtx);
0353       rtems_test_assert(status == thrd_success);
0354       next_generation(ctx);
0355 
0356       get_abs_timeout(&to);
0357       status = cnd_timedwait(&ctx->cnd, &ctx->mtx, &to);
0358       rtems_test_assert(status == thrd_success);
0359       next_generation(ctx);
0360 
0361       status = mtx_unlock(&ctx->mtx);
0362       rtems_test_assert(status == thrd_success);
0363     }
0364 
0365     if ((events & EVENT_TSS) != 0) {
0366       void *val;
0367 
0368       status = tss_set(ctx->tss, &tss_val);
0369       rtems_test_assert(status == thrd_success);
0370 
0371       val = tss_get(ctx->tss);
0372       rtems_test_assert(val == &tss_val);
0373 
0374       rtems_task_exit();
0375       rtems_test_assert(0);
0376     }
0377   }
0378 }
0379 
0380 static void test(void)
0381 {
0382   test_context *ctx = &test_instance;
0383   rtems_status_code sc;
0384 
0385   test_init(ctx);
0386 
0387   ctx->low = rtems_task_self();
0388 
0389   sc = rtems_task_create(
0390     rtems_build_name('H', 'I', 'G', 'H'),
0391     1,
0392     RTEMS_MINIMUM_STACK_SIZE,
0393     RTEMS_DEFAULT_MODES,
0394     RTEMS_DEFAULT_ATTRIBUTES,
0395     &ctx->high
0396   );
0397   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0398 
0399   sc = rtems_task_start(ctx->high, high_task, 0);
0400   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0401 
0402   test_once(ctx);
0403   test_mtx(ctx);
0404   test_cnd(ctx);
0405   test_tss(ctx);
0406   test_thrd(ctx);
0407   test_destroy(ctx);
0408 }
0409 
0410 static void Init(rtems_task_argument arg)
0411 {
0412   TEST_BEGIN();
0413 
0414   test();
0415 
0416   TEST_END();
0417   rtems_test_exit(0);
0418 }
0419 
0420 #define CONFIGURE_MICROSECONDS_PER_TICK US_PER_TICK
0421 
0422 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0423 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0424 
0425 #define CONFIGURE_MAXIMUM_TASKS 4
0426 
0427 #define CONFIGURE_MAXIMUM_POSIX_KEYS 1
0428 #define CONFIGURE_MAXIMUM_POSIX_KEY_VALUE_PAIRS 1
0429 #define CONFIGURE_MAXIMUM_POSIX_THREADS 1
0430 
0431 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0432 
0433 #define CONFIGURE_INIT_TASK_PRIORITY 4
0434 #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
0435 
0436 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0437 
0438 #define CONFIGURE_SCHEDULER_NAME rtems_build_name('b', 'l', 'u', 'e')
0439 
0440 #define CONFIGURE_INIT
0441 
0442 #include <rtems/confdefs.h>