Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file POSIX Timer Test
0005  *
0006  *  This is a simple real-time applications which contains 3 periodic tasks.
0007  *
0008  *  Task A is an independent task.
0009  *
0010  *  Task B and C share a data.
0011  *
0012  *  Tasks are implemented as POSIX threads.
0013  *
0014  *  The share data is protected with a POSIX mutex.
0015  *
0016  *  Other POSIX facilities such as timers, condition, .. are also used.
0017  */
0018 
0019 /*
0020  *  COPYRIGHT (c) 1989-2009.
0021  *  On-Line Applications Research Corporation (OAR).
0022  *
0023  * Redistribution and use in source and binary forms, with or without
0024  * modification, are permitted provided that the following conditions
0025  * are met:
0026  * 1. Redistributions of source code must retain the above copyright
0027  *    notice, this list of conditions and the following disclaimer.
0028  * 2. Redistributions in binary form must reproduce the above copyright
0029  *    notice, this list of conditions and the following disclaimer in the
0030  *    documentation and/or other materials provided with the distribution.
0031  *
0032  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0033  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0034  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0035  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0036  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0037  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0038  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0039  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0040  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0041  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0042  * POSSIBILITY OF SUCH DAMAGE.
0043  */
0044 
0045 #ifdef HAVE_CONFIG_H
0046 #include "config.h"
0047 #endif
0048 
0049 #define CONFIGURE_INIT
0050 #include "system.h"
0051 #include <pthread.h>  /* thread facilities */
0052 #include <signal.h>   /* signal facilities */
0053 #include <unistd.h>   /* sleep facilities */
0054 #include <sched.h>    /* schedule facilities */
0055 #include <time.h>     /* time facilities */
0056 #include <stdio.h>    /* console facilities */
0057 #include <rtems/posix/timerimpl.h>
0058 #include <rtems/score/timespec.h>
0059 #include "pritime.h"
0060 
0061 const char rtems_test_name[] = "PSXTIMER 1";
0062 
0063 void StopTimer(
0064   timer_t  timer_id,
0065   struct   itimerspec *timerdata
0066 );
0067 
0068 /* temporal parameters of a task */
0069 
0070 struct periodic_params {
0071    struct timespec period;
0072    int count;       /* Number of iterations to run */
0073    int signo;       /* signal number */
0074    int id;          /* task identification */
0075  };
0076 
0077 pthread_attr_t attr;
0078 
0079 /* shared datum */
0080 
0081 struct shared_data {
0082    pthread_mutex_t mutex;
0083    pthread_cond_t  sync;
0084    int updated;
0085  };
0086 
0087 struct shared_data data;
0088 
0089 void StopTimer(
0090   timer_t  timer_id,
0091   struct   itimerspec *timerdata
0092 )
0093 {
0094   static int         firstTime = 1;
0095   struct itimerspec *pOld;
0096   struct itimerspec  odata;
0097 
0098   /*
0099    *  We do not care about the old value.  But we need to exercise
0100    *  getting and not getting the return value back.
0101    */
0102   pOld = (firstTime == 1) ? NULL : &odata;
0103   firstTime = 0;
0104 
0105   timerdata->it_value.tv_sec  = 0;
0106   timerdata->it_value.tv_nsec  = 0;
0107   if (timer_settime(timer_id,POSIX_TIMER_RELATIVE,timerdata,pOld) == -1) {
0108     perror ("Error in timer setting\n");
0109     rtems_test_exit(0);
0110   }
0111 }
0112 
0113 /* task A  */
0114 void * task_a (void *arg)
0115 {
0116    struct   timespec my_period;
0117    int      my_sig, received_sig;
0118    struct   itimerspec timerdata;
0119    struct   itimerspec timergetdata;
0120    timer_t  timer_id;
0121    time_t   clock;
0122    struct   sigevent event;
0123    sigset_t set;
0124    struct periodic_params *params;
0125 
0126    params = arg;
0127    my_period = params->period;
0128    my_sig    = params->signo;
0129 
0130    /* timer create */
0131    event.sigev_notify = SIGEV_SIGNAL;
0132    event.sigev_signo = my_sig;
0133    if (timer_create (CLOCK_REALTIME, &event, &timer_id) == -1) {
0134       perror ("Error in timer creation\n");
0135       rtems_test_exit(0);
0136     }
0137 
0138    /* block the timer signal */
0139    sigemptyset (&set);
0140    sigaddset (&set,my_sig);
0141    pthread_sigmask(SIG_BLOCK,&set,NULL);
0142 
0143    /* set the timer in periodic mode */
0144    timerdata.it_interval = my_period;
0145    timerdata.it_value    = my_period;
0146    timerdata.it_value.tv_sec *= 2;
0147    if (timer_settime(timer_id,POSIX_TIMER_RELATIVE,&timerdata,&timergetdata) == -1) {
0148      perror ("Error in timer setting\n");
0149      rtems_test_exit(0);
0150    }
0151    printf(
0152     "task A: timer_settime - value=%" PRIdtime_t ":%ld interval=%" PRIdtime_t ":%ld\n",
0153     timergetdata.it_value.tv_sec, timergetdata.it_value.tv_nsec,
0154     timergetdata.it_interval.tv_sec, timergetdata.it_interval.tv_nsec
0155   );
0156 
0157 
0158    /* periodic activity */
0159    while(1) {
0160      if (sigwait(&set,&received_sig) == -1) {
0161        perror ("Error in sigwait\n");
0162      }
0163      if (timer_gettime(timer_id, &timerdata) == -1) {
0164        perror ("Error in timer_gettime\n");
0165        rtems_test_exit(0);
0166      }
0167      if (! _Timespec_Equal_to( &timerdata.it_value, &my_period )){
0168        fprintf(
0169            stderr, "Error in Task A timer_gettime:\n"
0170            "  re-armed timer: %" PRIdtime_t ":%ld does not match interval: %" PRIdtime_t ":%ld\n",
0171            timerdata.it_value.tv_sec, timerdata.it_value.tv_nsec,
0172            my_period.tv_sec, my_period.tv_nsec
0173       );
0174      }
0175      clock = time(NULL);
0176      printf("Executing task A with count = %2i %s", params->count, ctime(&clock));
0177      params->count--;
0178      if (params->count == 0)
0179        StopTimer(timer_id, &timerdata);
0180    }
0181    return NULL;
0182 }
0183 
0184 /* task B  */
0185 
0186 void * task_b (void *arg)
0187 {
0188    struct   timespec my_period;
0189    struct   timespec now;
0190    int      my_sig, received_sig;
0191    struct   itimerspec timerdata;
0192    timer_t  timer_id;
0193    time_t   clock;
0194    struct   sigevent event;
0195    sigset_t set;
0196    struct periodic_params *params;
0197 
0198    params = arg;
0199    my_period = params->period;
0200    my_sig    = params->signo;
0201 
0202 
0203    /* timer create */
0204    event.sigev_notify = SIGEV_SIGNAL;
0205    event.sigev_signo = my_sig;
0206    if (timer_create (CLOCK_REALTIME, &event, &timer_id) == -1) {
0207       perror ("Error in timer creation\n");
0208       rtems_test_exit(0);
0209     }
0210 
0211    /* block the timer signal */
0212    sigemptyset (&set);
0213    sigaddset (&set,my_sig);
0214    pthread_sigmask(SIG_BLOCK,&set,NULL);
0215 
0216    /* set the timer in periodic mode */
0217    clock_gettime( CLOCK_REALTIME, &now );
0218    timerdata.it_interval = my_period;
0219    timerdata.it_value = now;
0220    _Timespec_Add_to( &timerdata.it_value, &my_period );
0221    if (timer_settime(timer_id,TIMER_ABSTIME,&timerdata,NULL) == -1) {
0222      perror ("Error in timer setting\n");
0223      rtems_test_exit(0);
0224    }
0225 
0226    /* periodic activity */
0227    while(1) {
0228      if (sigwait(&set,&received_sig) == -1) {
0229        perror ("Error in sigwait\n");
0230        rtems_test_exit(0);
0231      }
0232 
0233      if (timer_gettime(timer_id, &timerdata) == -1) {
0234        perror ("Error in timer_gettime\n");
0235        rtems_test_exit(0);
0236      }
0237 
0238 #if 0
0239      /*
0240       *  It is not an error if they are not equal.  A clock tick could occur
0241       *  and thus they are close but not equal.  Can we test for this?
0242       */
0243      if ( !_Timespec_Equal_to( &timerdata.it_value, &my_period) ){
0244        printf( "NOT EQUAL %d:%d != %d:%d\n",
0245           timerdata.it_value.tv_sec,
0246           timerdata.it_value.tv_nsec,
0247           my_period.tv_sec,
0248           my_period.tv_nsec
0249        );
0250        rtems_test_exit(0);
0251      }
0252 #endif
0253 
0254      pthread_mutex_lock (&data.mutex);
0255      clock = time(NULL);
0256      printf("Executing task B with count = %2i %s",
0257        params->count, ctime(&clock)
0258      );
0259      data.updated = TRUE;
0260      pthread_cond_signal  (&data.sync);
0261      pthread_mutex_unlock (&data.mutex);
0262      params->count--;
0263      if (params->count == 0)
0264        StopTimer(timer_id, &timerdata);
0265    }
0266    return NULL;
0267 }
0268 
0269 /* task C */
0270 
0271 void * task_c (void *arg)
0272 {
0273    int      count;
0274    struct   timespec my_period;
0275    int      my_sig, received_sig;
0276    struct   itimerspec timerdata;
0277    struct   itimerspec timergetdata;
0278    timer_t  timer_id;
0279    time_t   clock;
0280    struct   sigevent event;
0281    sigset_t set;
0282    struct   periodic_params *params;
0283 
0284    params = arg;
0285    my_period = params->period;
0286    my_sig    = params->signo;
0287 
0288    /* timer create */
0289    event.sigev_notify = SIGEV_SIGNAL;
0290    event.sigev_signo = my_sig;
0291    if (timer_create (CLOCK_REALTIME, &event, &timer_id) == -1) {
0292       perror ("Error in timer creation\n");
0293       rtems_test_exit(0);
0294     }
0295 
0296    /* block the timer signal */
0297    sigemptyset (&set);
0298    sigaddset (&set,my_sig);
0299    pthread_sigmask(SIG_BLOCK,&set,NULL);
0300 
0301    /* set the timer in periodic mode */
0302    timerdata.it_interval = my_period;
0303    timerdata.it_value    = my_period;
0304    timerdata.it_value.tv_sec *= 2;
0305    if (timer_settime(timer_id,POSIX_TIMER_RELATIVE,&timerdata,NULL) == -1) {
0306      perror ("Error in timer setting\n");
0307      rtems_test_exit(0);
0308    }
0309 
0310    /* periodic activity */
0311    for (count=0 ; ; count++) {
0312       if (sigwait(&set,&received_sig) == -1) {
0313        perror ("Error in sigwait\n");
0314        rtems_test_exit(0);
0315      }
0316      if (timer_gettime(timer_id, &timerdata) == -1) {
0317        perror ("Error in timer_gettime\n");
0318        rtems_test_exit(0);
0319      }
0320      if (! _Timespec_Equal_to( &timerdata.it_value, &my_period) ){
0321        fprintf(
0322            stderr, "Error in Task A timer_gettime:\n"
0323            "  re-armed timer: %" PRIdtime_t ":%ld does not match interval: %" PRIdtime_t ":%ld\n",
0324            timerdata.it_value.tv_sec, timerdata.it_value.tv_nsec,
0325            my_period.tv_sec, my_period.tv_nsec
0326        );
0327      }
0328      pthread_mutex_lock (&data.mutex);
0329      while (data.updated == FALSE) {
0330        pthread_cond_wait (&data.sync,&data.mutex);
0331      }
0332      clock = time(NULL);
0333      printf("Executing task C with count = %2i %s",
0334        params->count, ctime(&clock)
0335      );
0336 
0337      if ( count && (count % 5) == 0 ) {
0338        int overruns = 0;
0339        sleep(1);
0340        overruns = timer_getoverrun( timer_id );
0341        printf( "task C: timer_getoverrun - overruns=%d\n", overruns );
0342 
0343        if (timer_gettime(timer_id, &timergetdata) == -1) {
0344      perror ("Error in timer setting\n");
0345          rtems_test_exit(0);
0346        }
0347        printf(
0348          "task C: timer_gettime - %" PRIdtime_t ":%ld remaining from %" PRIdtime_t ":%ld\n",
0349          timergetdata.it_value.tv_sec, timergetdata.it_value.tv_nsec,
0350          timergetdata.it_interval.tv_sec, timergetdata.it_interval.tv_nsec
0351        );
0352      }
0353 
0354      pthread_mutex_unlock (&data.mutex);
0355      params->count--;
0356      if (params->count == 0)
0357        StopTimer(timer_id, &timerdata);
0358    }
0359    return NULL;
0360 }
0361 
0362 /* main */
0363 
0364 void *POSIX_Init (
0365   void *argument
0366 )
0367 
0368 {
0369    pthread_mutexattr_t mutexattr;    /* mutex attributes */
0370    pthread_condattr_t  condattr;     /* condition attributes */
0371    pthread_attr_t attr;              /* task attributes */
0372    pthread_t ta,tb,tc, tc1;          /* threads */
0373    sigset_t  set;                    /* signals */
0374 
0375    struct sched_param sch_param;     /* schedule parameters */
0376    struct periodic_params params_a, params_b, params_c, params_c1;
0377 
0378    TEST_BEGIN();
0379 
0380    data.updated = FALSE;
0381 
0382    /* mask signal */
0383    sigemptyset (&set);
0384    sigaddset (&set,SIGALRM);
0385    pthread_sigmask (SIG_BLOCK,&set,NULL);
0386 
0387    /* set mutex attributes */
0388    if (pthread_mutexattr_init (&mutexattr) != 0) {
0389      perror ("Error in mutex attribute init\n");
0390    }
0391 
0392    /* init mutex */
0393    if (pthread_mutex_init (&data.mutex,&mutexattr) != 0) {
0394      perror ("Error in mutex init");
0395    }
0396 
0397     /* init condition attributes */
0398    if (pthread_condattr_init (&condattr) != 0) {
0399      perror ("Error in condition attribute init\n");
0400    }
0401 
0402    /* init condition */
0403    if (pthread_cond_init (&data.sync,&condattr) != 0) {
0404      perror ("Error in condition init");
0405    }
0406 
0407    /* init task attributes */
0408    if (pthread_attr_init(&attr) != 0) {
0409      perror ("Error in attribute init\n");
0410    }
0411 
0412    /* set explicit schedule for every task */
0413    if (pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED) != 0) {
0414       perror("Error in attribute inheritsched\n");
0415    }
0416 
0417    /* set task independent (join will not use) */
0418    if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) != 0) {
0419       perror ("Error in attribute detachstate\n");
0420    }
0421 
0422    /* schedule policy POSIX_FIFO (priority preemtive and FIFO within the same
0423       priority) */
0424    if (pthread_attr_setschedpolicy (&attr, SCHED_FIFO) != 0) {
0425       perror ("Error in attribute setschedpolicy\n");
0426     }
0427 
0428    /* set and create thread A with priority 1 */
0429 
0430    sch_param.sched_priority = 1;
0431    if (pthread_attr_setschedparam(&attr, &sch_param) != 0) {
0432       perror ("Error in attribute schedparam\n");
0433     }
0434 
0435    /* Temporal parameters (1 sec. periodicity) */
0436 
0437    params_a.period.tv_sec  = 1;         /* seconds */
0438    params_a.period.tv_nsec = 000000000; /* nanoseconds */
0439    params_a.count          = 20;
0440    params_a.signo = SIGALRM;
0441    if (pthread_create (&ta, &attr, task_a, &params_a) != 0 ) {
0442      perror ("Error in thread create for task a\n");
0443    }
0444 
0445    /* set and create thread B with priority 15 */
0446 
0447    sch_param.sched_priority = 15;
0448    if (pthread_attr_setschedparam(&attr, &sch_param) != 0) {
0449       perror ("Error in attribute schedparam");
0450     }
0451 
0452    /* Temporal parameters (2 sec. periodicity) */
0453    params_b.period.tv_sec  = 2;         /* seconds */
0454    params_b.period.tv_nsec = 000000000; /* nanoseconds */
0455    params_b.count          = 10;
0456    params_b.signo = SIGALRM;
0457    if (pthread_create (&tb, &attr, task_b, &params_b) != 0) {
0458      perror ("Error in thread create for task b\n");
0459    }
0460 
0461    /* set and create thread B with priority 14 */
0462 
0463    sch_param.sched_priority = 14;
0464    if (pthread_attr_setschedparam(&attr, &sch_param) != 0 ) {
0465       perror ("Error in attribute schedparam\n");
0466     }
0467 
0468    /* Temporal parameters (3 sec. periodicity) */
0469    params_c.period.tv_sec  = 3;         /* seconds */
0470    params_c.period.tv_nsec = 000000000; /* nanoseconds */
0471    params_c.count          = 6;
0472    params_c.signo = SIGALRM;
0473    if (pthread_create (&tc, &attr, task_c, &params_c) != 0) {
0474      perror ("Error in thread create for task c\n");
0475    }
0476 
0477    /* execute 25 seconds and finish */
0478    sleep (25);
0479 
0480    puts( "starting C again with 0.5 second periodicity" );
0481    /* Temporal parameters (0.5 sec. periodicity) */
0482    params_c1.period.tv_sec  = 0;         /* seconds */
0483    params_c1.period.tv_nsec = 500000000; /* nanoseconds */
0484    params_c1.count          = 6;
0485    params_c1.signo = SIGALRM;
0486    if (pthread_create (&tc1, &attr, task_c, &params_c1) != 0) {
0487      perror ("Error in thread create for task c1\n");
0488    }
0489 
0490    sleep(5);
0491 
0492    TEST_END();
0493    rtems_test_exit (0);
0494  }