Example
From ChronOS Linux
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 */
<code>#include <pthread.h>
- include <sys/types.h>
- include <unistd.h>
- include "libchronos/chronos.h"
</code>
/* 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;
}