Example
From ChronOS Linux
(Difference between revisions)
												
			
		| Line 2: | Line 2: | ||
<code>    | <code>    | ||
| - | /*  | + |  /*  | 
  * Antonio Barbalace  |   * Antonio Barbalace  | ||
  * periodic segments benchmark  |   * periodic segments benchmark  | ||
| Line 10: | Line 10: | ||
  * This version is terrible system with just one periodic thread  |   * This version is terrible system with just one periodic thread  | ||
  */  |   */  | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | #  | + |  #include <pthread.h>  | 
| - | #  | + |  #include <sys/types.h>  | 
| - | #  | + |  #include <unistd.h>  | 
| + |  #include "libchronos/chronos.h"  | ||
| - | #define   | + |  /* PARAMETERS */  | 
| - | #define   | + |  #define SET_SCHED_ALGO        SCHED_RT_RMA  | 
| + |  //#define SET_SCHED_FLAG        (SCHED_FLAG_PI | SCHED_FLAG_HUA | SCHED_FLAG_NO_DEADLOCKS)  | ||
| + |  #define SET_SCHED_FLAG        0  | ||
| + |  #define SET_SCHED_PRIO        ((SET_SCHED_ALGO & SCHED_GLOBAL_MASK) ? TASK_RUN_PRIO : -1)  | ||
| + |  #define SET_SCHED_PROC        0  | ||
| - | + |  #define UTIL                50  | |
| - | #define   | + |  #define PERIOD              1000000  | 
| - | #define   | + |  #define EXEC                   50   | 
| - | + |  #define JOBS_NUM            32  | |
| - | + |  #define ITER_NUM            4096  | |
| - | + | ||
| - | + | ||
| - | #define   | + | |
| - | #define   | + | |
| - | /*   | + |  /* macros to set or zero cpus in a cpu mask */  | 
| - | #define   | + |  #define MASK_ZERO(mask) (mask) = 0  | 
| - | #define   | + |  #define MASK_SET(mask, cpu) (mask) |= (unsigned long) pow(2, cpu)  | 
| - | + | ||
| - | + |  /* TASK_xxx_PRIO */  | |
| - | + |  #define MAIN_PRIO                       98  | |
| + |  #define TASK_CREATE_PRIO                96  | ||
| + |  #define TASK_START_PRIO                 94  | ||
| + |  #define TASK_CLEANUP_PRIO               92  | ||
| + |  #define TASK_RUN_PRIO                   90   | ||
| - | static inline long long timespec_subtract_us(struct timespec *x,  | + |  /* Numerical definitions */  | 
| - | + |  #define THOUSAND   1000  | |
| - | {  | + |  #define MILLION    1000000  | 
| + |  #define BILLION    1000000000   | ||
| + | |||
| + |  static pthread_attr_t attr;  | ||
| + |  static struct sched_param tparam;  | ||
| + | |||
| + |  static inline long long timespec_subtract_us(struct timespec *x,  | ||
| + |                           struct timespec *y)  | ||
| + |  {  | ||
     long long sec, nsec;  |      long long sec, nsec;  | ||
     sec = x->tv_sec - y->tv_sec;  |      sec = x->tv_sec - y->tv_sec;  | ||
| Line 63: | Line 61: | ||
     return (sec * MILLION) + (nsec / THOUSAND);  |      return (sec * MILLION) + (nsec / THOUSAND);  | ||
| - | }  | + |  }  | 
| - | static void find_job_deadline(int job, long period, struct timespec * start_time, struct timespec *deadline)  | + |  static void find_job_deadline(int job, long period, struct timespec * start_time, struct timespec *deadline)  | 
| - | {  | + |  {  | 
     unsigned long long nsec, carry;  |      unsigned long long nsec, carry;  | ||
     unsigned long offset = (job + 1) * period;    //the offset from the start time this deadline is  |      unsigned long offset = (job + 1) * period;    //the offset from the start time this deadline is  | ||
| Line 75: | Line 73: | ||
     deadline->tv_nsec = nsec % BILLION;  |      deadline->tv_nsec = nsec % BILLION;  | ||
     deadline->tv_sec = start_time->tv_sec + carry;  |      deadline->tv_sec = start_time->tv_sec + carry;  | ||
| - | }  | + |  }  | 
| - | void *start_task(void *arg)  | + |  void *start_task(void *arg)  | 
| - | {  | + |  {  | 
     int job;  |      int job;  | ||
     long period = PERIOD;  |      long period = PERIOD;  | ||
| Line 88: | Line 86: | ||
     tperiod.tv_nsec = (PERIOD % MILLION) * THOUSAND;  |      tperiod.tv_nsec = (PERIOD % MILLION) * THOUSAND;  | ||
| - | //    struct task *t = (struct task *)arg;  | + |  //    struct task *t = (struct task *)arg;  | 
     pid_t tid, pid;  |      pid_t tid, pid;  | ||
     long long tardiness;  |      long long tardiness;  | ||
| Line 110: | Line 108: | ||
     clock_gettime(CLOCK_REALTIME, &start_time);  |      clock_gettime(CLOCK_REALTIME, &start_time);  | ||
| - | // periodic LOOP  | + |  // periodic LOOP  | 
     for (job = 0; job<JOBS_NUM; job++) {  |      for (job = 0; job<JOBS_NUM; job++) {  | ||
         find_job_deadline(job, period, &start_time, &deadline);    //find the deadline for this taskset  |          find_job_deadline(job, period, &start_time, &deadline);    //find the deadline for this taskset  | ||
| Line 116: | Line 114: | ||
         //enter real-time segment  |          //enter real-time segment  | ||
| - | //        long begin_rtseg_self(int prio, int max_util, struct timespec* deadline,  | + |  //        long begin_rtseg_self(int prio, int max_util, struct timespec* deadline,  | 
                     //struct timespec* period, unsigned long exec_time);  |                      //struct timespec* period, unsigned long exec_time);  | ||
         begin_rtseg_self(TASK_RUN_PRIO, UTIL, &deadline, &tperiod, EXEC);  |          begin_rtseg_self(TASK_RUN_PRIO, UTIL, &deadline, &tperiod, EXEC);  | ||
| Line 143: | Line 141: | ||
     pthread_exit(NULL);  |      pthread_exit(NULL);  | ||
| - | }  | + |  }  | 
| - | int main(int argc, char* argv[]) {  | + |  int main(int argc, char* argv[]) {  | 
     int i;  |      int i;  | ||
| Line 193: | Line 191: | ||
     sched_setscheduler(0, SCHED_OTHER, &old_param);  |      sched_setscheduler(0, SCHED_OTHER, &old_param);  | ||
     return 0;  |      return 0;  | ||
| - | }  | + |  }  | 
</code>  | </code>  | ||
Revision as of 19:57, 17 April 2014
There are maybe better examples but this illustrates the fundamental idea/schema to write a real-time periodic task in ChronOS?. You will learn how to write a real-time task (locking the memory, i.e. do not allow the OS to swap the application memory) pin a task to a cpu (affinity mask).. all within ChronOS?!
 
/* * Antonio Barbalace * periodic segments benchmark * this work was done in the integration phase of the AUV code with ChronOS * * The whole code derive from the sched_test_app (Aaron version) * This version is terrible system with just one periodic thread */
#include <pthread.h> #include <sys/types.h> #include <unistd.h> #include "libchronos/chronos.h"
/* PARAMETERS */ #define SET_SCHED_ALGO SCHED_RT_RMA //#define SET_SCHED_FLAG (SCHED_FLAG_PI | SCHED_FLAG_HUA | SCHED_FLAG_NO_DEADLOCKS) #define SET_SCHED_FLAG 0 #define SET_SCHED_PRIO ((SET_SCHED_ALGO & SCHED_GLOBAL_MASK) ? TASK_RUN_PRIO : -1) #define SET_SCHED_PROC 0
#define UTIL 50 #define PERIOD 1000000 #define EXEC 50
#define JOBS_NUM 32 #define ITER_NUM 4096
/* macros to set or zero cpus in a cpu mask */ #define MASK_ZERO(mask) (mask) = 0 #define MASK_SET(mask, cpu) (mask) |= (unsigned long) pow(2, cpu)
/* TASK_xxx_PRIO */ #define MAIN_PRIO 98 #define TASK_CREATE_PRIO 96 #define TASK_START_PRIO 94 #define TASK_CLEANUP_PRIO 92 #define TASK_RUN_PRIO 90
/* Numerical definitions */ #define THOUSAND 1000 #define MILLION 1000000 #define BILLION 1000000000
static pthread_attr_t attr; static struct sched_param tparam;
static inline long long timespec_subtract_us(struct timespec *x,
                         struct timespec *y)
{
   long long sec, nsec;
   sec = x->tv_sec - y->tv_sec;
   nsec = x->tv_nsec - y->tv_nsec;
   if (nsec < 0) {
       nsec += BILLION;
       sec--;
   }
return (sec * MILLION) + (nsec / THOUSAND); }
static void find_job_deadline(int job, long period, struct timespec * start_time, struct timespec *deadline)
{
   unsigned long long nsec, carry;
   unsigned long offset = (job + 1) * period;    //the offset from the start time this deadline is
nsec = start_time->tv_nsec + offset * THOUSAND; carry = nsec / BILLION;
deadline->tv_nsec = nsec % BILLION; deadline->tv_sec = start_time->tv_sec + carry; }
void *start_task(void *arg)
{
   int job;
   long period = PERIOD;
   long i, l;
   struct sched_param param;
   struct timespec start_time, end_time, deadline, release, tperiod;
tperiod.tv_sec = PERIOD / MILLION; tperiod.tv_nsec = (PERIOD % MILLION) * THOUSAND;
// struct task *t = (struct task *)arg; pid_t tid, pid; long long tardiness; unsigned long thread_mask = SET_SCHED_PROC;
   //tid = gettid(); //get our thread's tid
   //pid = getpid(); //same as gettid
   //printf("tid %d pid %d\n", tid, pid);
   //set the affinity of this thread to whatever was specified in the taskset file
   if(sched_setaffinity(0, sizeof(thread_mask), (cpu_set_t *) &thread_mask)) {
       printf("Failed to set processor affinity of a task.");
       pthread_exit(0);
   }
//increase priority to TASK_START_PRIO param.sched_priority = TASK_START_PRIO; pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
//get the start time and CAS on the start-time so all the threads agree on when they got here clock_gettime(CLOCK_REALTIME, &start_time);
// periodic LOOP
   for (job = 0; job<JOBS_NUM; job++) {
       find_job_deadline(job, period, &start_time, &deadline);    //find the deadline for this taskset
       clock_gettime(CLOCK_REALTIME, &release);    // real release time
       //enter real-time segment
//        long begin_rtseg_self(int prio, int max_util, struct timespec* deadline,
                   //struct timespec* period, unsigned long exec_time);
       begin_rtseg_self(TASK_RUN_PRIO, UTIL, &deadline, &tperiod, EXEC);
       // DO SOMETHING like a printf... :-)
       printf("job %d\n", job);
       l = 123456789;
       for (i=0; i< ITER_NUM; i++) {
           l *= i;
           // or nop
       }
       i = l;
       //end real time segment
       clock_gettime(CLOCK_REALTIME, &end_time);    //get the endtime
       end_rtseg_self(TASK_CLEANUP_PRIO);    //end the real-time segment
tardiness = timespec_subtract_us(&deadline, &end_time); //calculate tardiness from deadline and endtime
       if (tardiness >= 0) {    //otherwise, did we meet our deadline?
           //sleep for however much time remains before the next release of this task
           if (tardiness > 0)
               usleep(tardiness);
       }
   }
pthread_exit(NULL); }
int main(int argc, char* argv[]) {
int i; struct sched_param param, old_param; unsigned long main_mask = 0; pthread_t thread;
//TODO we have to put mem lock all and mem unlock all at the end
   //set outselves as a real-time task
   sched_getparam(0, &old_param);
   param.sched_priority = MAIN_PRIO;
   if (sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
       printf("sched_setscheduler() failed.");
       return 0;
   }
   //set task affinity of this main thread to the first processor
   MASK_ZERO(main_mask);
   MASK_SET(main_mask, 0);
   if (sched_setaffinity(0, sizeof(main_mask), (cpu_set_t *) & main_mask)
       < 0) {
       printf("sched_setaffinity() failed.");
       return 0;
   }
   if (set_scheduler(SET_SCHED_ALGO | SET_SCHED_FLAG, SET_SCHED_PRIO, SET_SCHED_PROC)) {
           printf("Selection of RT scheduler failed! Is the scheduler loaded?");
           return 0;
   }
tparam.sched_priority = TASK_CREATE_PRIO; pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); pthread_attr_setschedparam(&attr, &tparam);
   if (pthread_create(thread, &attr, start_task,0)) {
           printf("Failed to pthread_create one of the task threads.");
           return 0;
   }
   if (pthread_join(thread, NULL)) {
       printf("Failed to pthread_join one of the task threads.");
       return 0;
   }
//return us to a normal scheduler and priority sched_setscheduler(0, SCHED_OTHER, &old_param); return 0; }
