User Tools

Site Tools


realtime:documentation:howto:applications:cyclic

This is an old revision of the document!


HOWTO build a basic cyclic application

The cyclic RT task will use the basic application task which was built in the previous section (HOWTO build a simple RT application).

Cyclic Task

A cyclic task is one which is repeated after a fixed period of time like reading sensor data every 100 ms. The execution time for the cyclic task should always be less than the period of the task. Following are the mechanisms which we will be looking at for implementing cyclic task:

  • nanosleep
  • EDF Scheduling

Current Time

There are multiple ways to get current time – gettimeofday, time, clock_gettime, and some other processor specific implementations. Some of them, like gettimeofday, will get time from the system clock. The system clock can be modified by other processes. Which means that the clock can go back in time. clock_gettime with CLOCK_MONOTONIC clock can be used to avoid this problem. CLOCK_MONOTONIC argument ensures that we get a nonsettable monotonically increasing clock that measures time from some unspecified point in the past that does not change after system startup[1]. It is also important to ensure we do not waste a lot of CPU cycles to get the current time. CPU specific implementations to get the current time will be helpful here.

Basic Stub

Any mechanism for implementing a cyclic task can be divided into the following parts:

  • periodic_task_init(): initialization code for doing things like requesting timers, initializing variables, setting timer periods.
  • do_rt_task(): The real time task is done here.
  • wait_rest_of_period(): After the task is done, wait for the rest of the period. The assumption here is the task less time to complete compared to the period length.
  • struct period_info: this is a struct which will be used to pass around data required by the above mentioned functions.

The stub for the real time task will look like:

void *simple_cyclic_task(void *data)
{
        struct period_info pinfo;
 
        periodic_task_init(&pinfo);
 
        while (1) {
                do_rt_task();
                wait_rest_of_period(&pinfo);
        }
}

Examples

clock_nanosleep

clock_nanosleep() is used to ask the process to sleep for certain amount of time. nanosleep() can also be used to sleep. But, nanosleep() uses CLOCK_REALTIME which can be changed by another processes and hence can be discontinuous or jump back in time. In clock_nanosleep, CLOCK_MONOTONIC is explicitly specified. This is a immutable clock which does not change after startup. The periodicity is achieved by recording time before and after the task is implemented and sleeping for the difference between period length and execution time (determined by difference in the timestamps taken before RT task has started and after it has completed.) more information on clock_nanosleep at http://man7.org/linux/man-pages/man2/clock_nanosleep.2.html

struct period_info{
        struct timespec start_time;
        struct timespec time_elapsed;
};
 
void periodic_task_init(struct period_info *pinfo)
{
        clock_gettime(CLOCK_MONOTONIC, &(pinfo->start_time));
}
 
void do_rt_work()
{
        //Do RT stuff here.
}
 
// Assuming the timespec_a is always greater than timespec_b.
struct timespec time_difference(struct timespec *a, struct timespec *b)
{
        struct timespec diff;
 
        diff.tv_sec = a->tv_sec - b->tv_sec;
        diff.tv_nsec = a->tv_nsec - b->tv_nsec;
 
        if (diff.tv_nsec < 0)
        {
                diff.tv_sec--;
                diff.tv_nsec += 1000000000;
        }
 
        return diff;
}
 
void wait_rest_of_period(struct period_info *pinfo, struct timespec *period_length)
{
        //Determine how much time has passed.
        //Wait for the rest of the period.
        struct timespec current_time, time_elapsed, remaining_time;
 
        clock_gettime(CLOCK_MONOTONIC, &current_time);
 
        time_elapsed = time_difference(&current_time, &pinfo->start_time);
        // Assuming that the task execution time is less than period_length.
        remaining_time = time_difference(period_length, &time_elapsed);
 
        clock_nanosleep(CLOCK_MONOTONIC, 0, &remaining_time, NULL);
 
        // Starting the next period.
        clock_gettime(CLOCK_MONOTONIC, &pinfo->start_time);
}

EDF Scheduler

Recently, earliest deadline first scheduling algorithm has been merged in the mainline kernel. Now, users can specify runtime, period and deadline of a task and they scheduler will run the task every specified period and will make sure the deadline is met. The scheduler will also let user know if the tasks(or a set of tasks) cannot be scheduled because the deadline won't be met.

More information about the EDF scheduler including an example of implementation can be found at: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/scheduler/sched-deadline.txt?id=refs/tags/v4.10-rc2

realtime/documentation/howto/applications/cyclic.1495206750.txt.gz · Last modified: 2017/05/19 15:12 by jogness