Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  COPYRIGHT (c) 1989-2012.
0005  *  On-Line Applications Research Corporation (OAR).
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  *
0016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0019  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0020  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0021  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0022  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0025  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0026  * POSSIBILITY OF SUCH DAMAGE.
0027  */
0028 
0029 #ifdef HAVE_CONFIG_H
0030 #include "config.h"
0031 #endif
0032 
0033 #include <time.h>
0034 #include <errno.h>
0035 #include <stdint.h>
0036 
0037 #include "pmacros.h"
0038 #include "pritime.h"
0039 
0040 #include <rtems.h>
0041 #include <rtems/score/todimpl.h>
0042 
0043 const char rtems_test_name[] = "PSXCLOCK";
0044 
0045 static void check_enosys(int status)
0046 {
0047   if ( (status == -1) && (errno == ENOSYS) )
0048     return;
0049   puts( "ERROR -- did not return ENOSYS as expected" );
0050   rtems_test_exit(0);
0051 }
0052 
0053 static void wait_ticks( rtems_interval ticks )
0054 {
0055   /*
0056    * Avoid any clock related sleep calls
0057    */
0058   rtems_test_assert( rtems_task_wake_after( ticks ) == RTEMS_SUCCESSFUL );
0059 }
0060 
0061 struct clock_context;
0062 typedef struct clock_context clock_context;
0063 typedef void (*clock_sleeper)(clock_context* ctx);
0064 struct clock_context {
0065   const char* name;
0066   int instance;
0067   rtems_id tid;
0068   int counter;
0069   int result;
0070   rtems_interval ticks;
0071   struct timespec tspec;
0072   clock_sleeper sleeper;
0073 };
0074 
0075 static void clock_context_init(
0076   clock_context* ctx, const char* name, int instance,
0077   time_t secs, long nsecs, clock_sleeper sleeper)
0078 {
0079   memset( ctx, 0, sizeof( *ctx ) );
0080   ctx->name = name;
0081   ctx->instance = instance;
0082   ctx->tspec.tv_sec = secs;
0083   ctx->tspec.tv_nsec = nsecs;
0084   ctx->sleeper = sleeper;
0085 }
0086 
0087 static void test_nanosleep( clock_context* ctx )
0088 {
0089   if ( nanosleep ( &ctx->tspec, NULL ) < 0 )
0090   {
0091     ctx->result = errno;
0092   }
0093 }
0094 
0095 static void test_clock_nanosleep_realtime( clock_context* ctx )
0096 {
0097   if ( clock_nanosleep ( CLOCK_REALTIME, 0, &ctx->tspec, NULL ) < 0 )
0098   {
0099     ctx->result = errno;
0100   }
0101 }
0102 
0103 static void test_clock_nanosleep_monotonic( clock_context* ctx )
0104 {
0105   if ( clock_nanosleep ( CLOCK_MONOTONIC, 0, &ctx->tspec, NULL ) < 0 )
0106   {
0107     ctx->result = errno;
0108   }
0109 }
0110 
0111 static void test_clock_check( clock_context* ctx, const rtems_interval ticks_per_sec )
0112 {
0113   const long tick_period_nsec = 1000000000LLU / ticks_per_sec;
0114   rtems_interval ticks =
0115     (((ctx->tspec.tv_sec * 1000000000LLU) + ctx->tspec.tv_nsec) / tick_period_nsec) + 1;
0116   rtems_test_assert( ctx->result == 0 );
0117   printf(
0118     "clock: %s: sec=%" PRIdtime_t" nsec=%li ticks=%u expected-ticks=%u\n",
0119     ctx->name, ctx->tspec.tv_sec, ctx->tspec.tv_nsec, ctx->ticks, ticks);
0120   rtems_test_assert( ctx->ticks == ticks );
0121 }
0122 
0123 static void task_clock( rtems_task_argument arg )
0124 {
0125   clock_context* ctx = (clock_context*) arg;
0126   rtems_interval start = rtems_clock_get_ticks_since_boot();
0127   rtems_interval end;
0128   ctx->result = 0;
0129   ctx->sleeper( ctx );
0130   end = rtems_clock_get_ticks_since_boot();
0131   ctx->ticks = end - start;
0132   ++ctx->counter;
0133   rtems_task_delete( RTEMS_SELF );
0134 }
0135 
0136 static void test_start_task( clock_context* ctx )
0137 {
0138   rtems_status_code sc;
0139   sc = rtems_task_create(
0140     rtems_build_name( 'C', 'R', 'T', '0' + ctx->instance ),
0141     1,
0142     RTEMS_MINIMUM_STACK_SIZE,
0143     RTEMS_DEFAULT_MODES,
0144     RTEMS_DEFAULT_ATTRIBUTES,
0145     &ctx->tid
0146   );
0147   rtems_test_assert( sc == RTEMS_SUCCESSFUL );
0148   sc = rtems_task_start( ctx->tid, task_clock, (rtems_task_argument) ctx );
0149   rtems_test_assert( sc == RTEMS_SUCCESSFUL );
0150 }
0151 
0152 static void test_settime_and_sleeping_step( int step )
0153 {
0154   const rtems_interval ticks_per_sec = rtems_clock_get_ticks_per_second();
0155   struct timespec tv;
0156 
0157   clock_context ns_ctx;
0158   clock_context cnr_ctx;
0159   clock_context cnm_ctx;
0160 
0161   printf( "\nClock settime while sleeping: step=%i\n", step );
0162 
0163   clock_context_init(
0164     &ns_ctx, "nanosleep", 0, 0, 500000000,
0165     test_nanosleep );
0166   clock_context_init(
0167     &cnr_ctx, "clock_nanosleep(CLOCK_REALTIME)", 0, 0, 500000000,
0168     test_clock_nanosleep_realtime );
0169   clock_context_init(
0170     &cnm_ctx, "clock_nanosleep(CLOCK_MONOTONIC)", 0, 0, 500000000,
0171     test_clock_nanosleep_monotonic );
0172 
0173   /* Sat, 01 Jan 2000 00:00:00 GMT */
0174   tv.tv_sec = 946684800;
0175   tv.tv_nsec = 0;
0176   rtems_test_assert( clock_settime( CLOCK_REALTIME, &tv ) == 0 );
0177 
0178   wait_ticks( 1 );
0179 
0180   test_start_task( &ns_ctx );
0181   test_start_task( &cnr_ctx );
0182   test_start_task( &cnm_ctx );
0183 
0184   wait_ticks( 2 );
0185 
0186   /*
0187    * Jump forwards 1 second
0188    */
0189   if ( step != 0 )
0190   {
0191     tv.tv_sec = 946684800 + step;
0192     tv.tv_nsec = 0;
0193     rtems_test_assert( clock_settime( CLOCK_REALTIME, &tv ) == 0 );
0194   }
0195 
0196   while (true)
0197   {
0198     int counts = 0;
0199     wait_ticks( ticks_per_sec /  4 );
0200     counts += ns_ctx.counter;
0201     counts += cnr_ctx.counter;
0202     counts += cnm_ctx.counter;
0203     if (counts == 3)
0204     {
0205       break;
0206     }
0207   }
0208 
0209   test_clock_check( &ns_ctx, ticks_per_sec );
0210   test_clock_check( &cnr_ctx, ticks_per_sec );
0211   test_clock_check( &cnm_ctx, ticks_per_sec );
0212 }
0213 
0214 static void test_settime_and_sleeping( void )
0215 {
0216   test_settime_and_sleeping_step( 0 );
0217   test_settime_and_sleeping_step( 1 );
0218   test_settime_and_sleeping_step( -1 );
0219 }
0220 
0221 typedef struct {
0222   int counter;
0223   struct timespec delta;
0224 } nanosleep_contex;
0225 
0226 static void task_nanosleep( rtems_task_argument arg )
0227 {
0228   nanosleep_contex *ctx;
0229 
0230   ctx = (nanosleep_contex *) arg;
0231   ++ctx->counter;
0232   nanosleep( &ctx->delta, NULL );
0233 }
0234 
0235 static void test_far_future_nanosleep( void )
0236 {
0237   rtems_status_code sc;
0238   rtems_id          id;
0239   nanosleep_contex  ctx;
0240 
0241   sc = rtems_task_create(
0242     rtems_build_name( 'N', 'A', 'N', 'O' ),
0243     1,
0244     RTEMS_MINIMUM_STACK_SIZE,
0245     RTEMS_DEFAULT_MODES,
0246     RTEMS_DEFAULT_ATTRIBUTES,
0247     &id
0248   );
0249   rtems_test_assert( sc == RTEMS_SUCCESSFUL );
0250 
0251   ctx.counter = 0;
0252   ctx.delta.tv_sec = INT64_MAX;
0253   ctx.delta.tv_nsec = 999999999;
0254   sc = rtems_task_start( id, task_nanosleep, (rtems_task_argument) &ctx );
0255   rtems_test_assert( sc == RTEMS_SUCCESSFUL );
0256 
0257   sc = rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
0258   rtems_test_assert( sc == RTEMS_SUCCESSFUL );
0259 
0260   rtems_test_assert( ctx.counter == 1 );
0261 
0262   sc = rtems_task_delete( id );
0263   rtems_test_assert( sc == RTEMS_SUCCESSFUL );
0264 }
0265 
0266 static rtems_task Init(
0267   rtems_task_argument argument
0268 )
0269 {
0270   struct timespec tv;
0271   struct timespec tr;
0272   int             sc;
0273   time_t          seconds;
0274   time_t          seconds1;
0275   unsigned int    remaining;
0276   struct tm       tm;
0277   struct timespec delay_request;
0278 
0279   TEST_BEGIN();
0280 
0281   tm_build_time( &tm, TM_FRIDAY, TM_MAY, 24, 96, 11, 5, 0 );
0282 
0283   /* error cases in clock_gettime and clock_settime */
0284 
0285   puts( "Init: clock_gettime - EINVAL (NULL timespec)" );
0286   errno = 0;
0287   sc = clock_gettime( CLOCK_REALTIME, NULL );
0288   rtems_test_assert( sc == -1 );
0289   rtems_test_assert( errno == EINVAL );
0290 
0291   puts( "Init: clock_gettime - EINVAL (invalid clockid)" );
0292   errno = 0;
0293   sc = clock_gettime( (clockid_t)-1, &tv );
0294   rtems_test_assert( sc == -1 );
0295   rtems_test_assert( errno == EINVAL );
0296 
0297   puts( "Init: clock_settime - EINVAL (invalid clockid)" );
0298   errno = 0;
0299   sc = clock_settime( (clockid_t)-1, &tv );
0300   rtems_test_assert( sc == -1 );
0301   rtems_test_assert( errno == EINVAL );
0302 
0303   /* way back near the dawn of time :D */
0304   tv.tv_sec = 1;
0305   tv.tv_nsec = 0;
0306   printf( ctime( &tv.tv_sec ) );
0307   puts( "Init: clock_settime - before 1988 EINVAL" );
0308   errno = 0;
0309   sc = clock_settime( CLOCK_REALTIME, &tv );
0310   rtems_test_assert( sc == -1 );
0311   rtems_test_assert( errno == EINVAL );
0312 
0313   puts( "Init: clock_settime - invalid nanoseconds EINVAL" );
0314   tv.tv_sec = 946681200;
0315   tv.tv_nsec = 2000000000;
0316   errno = 0;
0317   sc = clock_settime( CLOCK_REALTIME, &tv );
0318   rtems_test_assert( sc == -1 );
0319   rtems_test_assert( errno == EINVAL );
0320 
0321   puts( "Init: clock_settime - 2400-01-01T00:00:00.999999999Z SUCCESSFUL" );
0322   tv.tv_sec = 13569465600;
0323   tv.tv_nsec = 999999999;
0324   sc = clock_settime( CLOCK_REALTIME, &tv );
0325   rtems_test_assert( sc == 0 );
0326 
0327   puts( "Init: clock_settime - 2400-01-01T00:00:01Z EINVAL" );
0328   tv.tv_sec = 13569465601;
0329   tv.tv_nsec = 0;
0330   errno = 0;
0331   sc = clock_settime( CLOCK_REALTIME, &tv );
0332   rtems_test_assert( sc == -1 );
0333   rtems_test_assert( errno == EINVAL );
0334 
0335   puts( "Init: clock_settime - far future EINVAL" );
0336   tv.tv_sec = 17179869184;
0337   tv.tv_nsec = 0;
0338   errno = 0;
0339   sc = clock_settime( CLOCK_REALTIME, &tv );
0340   rtems_test_assert( sc == -1 );
0341   rtems_test_assert( errno == EINVAL );
0342 
0343   /* exercise clock_getres */
0344 
0345   puts( "Init: clock_getres - EINVAL (invalid clockid)" );
0346   errno = 0;
0347   sc = clock_getres( (clockid_t) -1, &tv );
0348   rtems_test_assert( sc == -1 );
0349   rtems_test_assert( errno == EINVAL );
0350 
0351   puts( "Init: clock_getres - EINVAL (NULL resolution)" );
0352   errno = 0;
0353   sc = clock_getres( CLOCK_REALTIME, NULL );
0354   rtems_test_assert( sc == -1 );
0355   rtems_test_assert( errno == EINVAL );
0356 
0357   puts( "Init: clock_getres - SUCCESSFUL" );
0358   sc = clock_getres( CLOCK_REALTIME, &tv );
0359   printf( "Init: resolution = sec (%" PRIdtime_t "), nsec (%ld)\n", tv.tv_sec, tv.tv_nsec );
0360   rtems_test_assert( !sc );
0361 
0362   /* set the time of day, and print our buffer in multiple ways */
0363 
0364   tv.tv_sec = mktime( &tm );
0365   rtems_test_assert( tv.tv_sec != -1 );
0366 
0367   tv.tv_nsec = 0;
0368 
0369   /* now set the time of day */
0370 
0371   empty_line();
0372 
0373   printf( asctime( &tm ) );
0374   puts( "Init: clock_settime - SUCCESSFUL" );
0375   sc = clock_settime( CLOCK_REALTIME, &tv );
0376   rtems_test_assert( !sc );
0377 
0378   printf( asctime( &tm ) );
0379   printf( ctime( &tv.tv_sec ) );
0380 
0381   /* use sleep to delay */
0382 
0383   remaining = sleep( 3 );
0384   rtems_test_assert( !remaining );
0385 
0386   /* print new times to make sure it has changed and we can get the realtime */
0387   sc = clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &tv );
0388   rtems_test_assert( !sc );
0389   printf("Time since boot: (%" PRIdtime_t ", %ld)\n", tv.tv_sec,tv.tv_nsec );
0390 
0391   sc = clock_gettime( CLOCK_REALTIME, &tv );
0392   rtems_test_assert( !sc );
0393 
0394   printf( ctime( &tv.tv_sec ) );
0395 
0396   seconds = time( NULL );
0397   printf( ctime( &seconds ) );
0398 
0399   /*  just to have the value copied out through the parameter */
0400 
0401   seconds = time( &seconds1 );
0402   rtems_test_assert( seconds == seconds1 );
0403 
0404   /* check the time remaining */
0405 
0406   printf( "Init: seconds remaining (%d)\n", (int)remaining );
0407   rtems_test_assert( !remaining );
0408 
0409   test_far_future_nanosleep();
0410 
0411   /* error cases in nanosleep */
0412 
0413   empty_line();
0414   puts( "Init: nanosleep - EINVAL (NULL time)" );
0415   sc = nanosleep ( NULL, &tr );
0416   rtems_test_assert( sc == -1 );
0417   rtems_test_assert( errno == EINVAL );
0418 
0419   tv.tv_sec = 0;
0420   tv.tv_nsec = TOD_NANOSECONDS_PER_SECOND * 2;
0421   puts( "Init: nanosleep - EINVAL (too many nanoseconds)" );
0422   errno = 0;
0423   sc = nanosleep ( &tv, &tr );
0424   rtems_test_assert( sc == -1 );
0425   rtems_test_assert( errno == EINVAL );
0426 
0427   /* this is an error */
0428   tv.tv_sec = -1;
0429   tv.tv_nsec = 0;
0430   puts( "Init: nanosleep - negative seconds - EINVAL" );
0431   errno = 0;
0432   sc = nanosleep ( &tv, &tr );
0433   rtems_test_assert( sc == -1 );
0434   rtems_test_assert( errno == EINVAL );
0435 
0436   /* this is also an error */
0437   tv.tv_sec = 0;
0438   tv.tv_nsec = -1;
0439   puts( "Init: nanosleep - negative nanoseconds - EINVAL" );
0440   errno = 0;
0441   sc = nanosleep ( &tv, &tr );
0442   rtems_test_assert( sc == -1 );
0443   rtems_test_assert( errno == EINVAL );
0444 
0445   /* this is actually a small delay */
0446   tv.tv_sec = 0;
0447   tv.tv_nsec = 1;
0448   puts( "Init: nanosleep - delay so small results in one tick" );
0449   sc = nanosleep ( &tv, &tr );
0450   rtems_test_assert( !sc );
0451   rtems_test_assert( !tr.tv_sec );
0452   rtems_test_assert( !tr.tv_nsec );
0453 
0454   /* use nanosleep to yield */
0455 
0456   tv.tv_sec = 0;
0457   tv.tv_nsec = 0;
0458 
0459   puts( "Init: nanosleep - yield with remaining" );
0460   sc = nanosleep ( &tv, &tr );
0461   rtems_test_assert( !sc );
0462   rtems_test_assert( !tr.tv_sec );
0463   rtems_test_assert( !tr.tv_nsec );
0464 
0465   puts( "Init: nanosleep - yield with NULL time remaining" );
0466   sc = nanosleep ( &tv, NULL );
0467   rtems_test_assert( !sc );
0468   rtems_test_assert( !tr.tv_sec );
0469   rtems_test_assert( !tr.tv_nsec );
0470 
0471   /* use nanosleep to delay */
0472 
0473   tv.tv_sec = 3;
0474   tv.tv_nsec = 500000;
0475 
0476   puts( "Init: nanosleep - 1.05 seconds" );
0477   sc = nanosleep ( &tv, &tr );
0478   rtems_test_assert( !sc );
0479 
0480   /* print the current real time again */
0481   sc = clock_gettime( CLOCK_REALTIME, &tv );
0482   rtems_test_assert( !sc );
0483   printf( ctime( &tv.tv_sec ) );
0484 
0485   /* check the time remaining */
0486 
0487   printf( "Init: sec (%" PRIdtime_t "), nsec (%ld) remaining\n", tr.tv_sec, tr.tv_nsec );
0488   rtems_test_assert( !tr.tv_sec && !tr.tv_nsec );
0489 
0490   puts( "Init: nanosleep - 1.35 seconds" );
0491   delay_request.tv_sec = 1;
0492   delay_request.tv_nsec = 35000000;
0493   sc = nanosleep( &delay_request, NULL );
0494   rtems_test_assert( !sc );
0495 
0496   /* print the current real time again */
0497   sc = clock_gettime( CLOCK_REALTIME, &tv );
0498   rtems_test_assert( !sc );
0499   printf( ctime( &tv.tv_sec ) );
0500 
0501   empty_line();
0502   puts( "clock_gettime - CLOCK_THREAD_CPUTIME_ID -- ENOSYS" );
0503   #if defined(_POSIX_THREAD_CPUTIME)
0504     {
0505       struct timespec tp;
0506       sc = clock_gettime( CLOCK_THREAD_CPUTIME_ID, &tp );
0507       check_enosys( sc );
0508     }
0509   #endif
0510 
0511   puts( "clock_settime - CLOCK_PROCESS_CPUTIME_ID -- ENOSYS" );
0512   #if defined(_POSIX_CPUTIME)
0513     {
0514       struct timespec tp;
0515       sc = clock_settime( CLOCK_PROCESS_CPUTIME_ID, &tp );
0516       check_enosys( sc );
0517     }
0518   #endif
0519 
0520   puts( "clock_settime - CLOCK_THREAD_CPUTIME_ID -- ENOSYS" );
0521   #if defined(_POSIX_THREAD_CPUTIME)
0522     {
0523       struct timespec tp;
0524       sc = clock_settime( CLOCK_THREAD_CPUTIME_ID, &tp );
0525       check_enosys( sc );
0526     }
0527   #endif
0528 
0529   test_settime_and_sleeping( );
0530 
0531   TEST_END();
0532   rtems_test_exit(0);
0533 }
0534 
0535 
0536 /* configuration information */
0537 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0538 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0539 
0540 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0541 
0542 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0543 #define CONFIGURE_MAXIMUM_TASKS             4
0544 
0545 #define CONFIGURE_INIT
0546 #include <rtems/confdefs.h>