#include <sys/wait.h> /* for waitpid() */
#include <unistd.h>
#include <stdio.h>
#include <math.h>
#include "tests.h"
#include "litmus.h"
TESTCASE(preempt_on_resume, P_FP | PSN_EDF,
"preempt lower-priority task when a higher-priority task resumes")
{
int child_hi, child_lo, status, waiters;
lt_t delay = ms2ns(100);
double start, stop;
struct rt_task params;
init_rt_task_param(¶ms);
params.cpu = 0;
params.exec_cost = ms2ns(10000);
params.period = ms2ns(100000);
child_lo = FORK_TASK(
params.priority = LITMUS_LOWEST_PRIORITY;
SYSCALL( set_rt_task_param(gettid(), ¶ms) );
SYSCALL( be_migrate_to_cpu(params.cpu) );
SYSCALL( task_mode(LITMUS_RT_TASK) );
SYSCALL( wait_for_ts_release() );
start = cputime();
while (cputime() - start < 10)
;
);
child_hi = FORK_TASK(
params.priority = LITMUS_HIGHEST_PRIORITY;
params.relative_deadline -= 1000000;
SYSCALL( set_rt_task_param(gettid(), ¶ms) );
SYSCALL( be_migrate_to_cpu(params.cpu) );
SYSCALL( task_mode(LITMUS_RT_TASK) );
SYSCALL( wait_for_ts_release() );
start = cputime();
while (cputime() - start < 0.1)
;
start = wctime();
SYSCALL( lt_sleep(ms2ns(100)) );
stop = wctime();
SYSCALL( kill(child_lo, SIGUSR2) );
if (stop - start >= 0.2)
fprintf(stderr, "\nHi-prio delay = %fsec\n",
stop - start - (ms2ns(100) / (float)s2ns(1)));
/* Assert we woke up 'soonish' after the sleep. */
ASSERT( stop - start < 0.2 );
);
do {
waiters = get_nr_ts_release_waiters();
ASSERT( waiters >= 0 );
} while (waiters != 2);
waiters = release_ts(&delay);
SYSCALL( waitpid(child_hi, &status, 0) );
ASSERT( status == 0 );
SYSCALL( waitpid(child_lo, &status, 0) );
ASSERT( status == SIGUSR2);
}
#define PERIOD 100 /* in ms */
#define JOBS 10
#define ACCEPTABLE_MARGIN 5 /* in ms --- must be largish for QEMU */
TESTCASE(jobs_are_rate_limited, LITMUS,
"periodic jobs are rate-limited (w/o synchronous release)")
{
struct rt_task params;
double start, end, actual_delta_ms;
int i;
init_rt_task_param(¶ms);
params.cpu = 0;
params.exec_cost = ms2ns(40);
params.period = ms2ns(PERIOD);
params.release_policy = TASK_PERIODIC;
SYSCALL( set_rt_task_param(gettid(), ¶ms) );
SYSCALL( be_migrate_to_cpu(params.cpu) );
SYSCALL( task_mode(LITMUS_RT_TASK) );
start = wctime();
for (i = 0; i < JOBS; i++)
SYSCALL( sleep_next_period() );
end = wctime();
SYSCALL( task_mode(BACKGROUND_TASK) );
actual_delta_ms = (end - start) * 1000.0;
if (fabs(JOBS * PERIOD - actual_delta_ms) > ACCEPTABLE_MARGIN)
fprintf(stderr, "actual_delta_ms:%.4f expected:%.4f\n",
actual_delta_ms, (double) (JOBS * PERIOD));
ASSERT( fabs(JOBS * PERIOD - actual_delta_ms) <= ACCEPTABLE_MARGIN);
}
TESTCASE(jobs_are_rate_limited_synch, LITMUS,
"periodic jobs are rate-limited (w/ synchronous release)")
{
struct rt_task params;
double start, end, actual_delta_ms;
int i;
int child, status, waiters;
lt_t delay = ms2ns(100);
child = FORK_TASK(
init_rt_task_param(¶ms);
params.cpu = 0;
params.exec_cost = ms2ns(5);
params.period = ms2ns(PERIOD);
params.release_policy = TASK_PERIODIC;
SYSCALL( set_rt_task_param(gettid(), ¶ms) );
SYSCALL( be_migrate_to_cpu(params.cpu) );
SYSCALL( task_mode(LITMUS_RT_TASK) );
SYSCALL( wait_for_ts_release() );
start = wctime();
for (i = 0; i < JOBS; i++)
SYSCALL( sleep_next_period() );
end = wctime();
SYSCALL( task_mode(BACKGROUND_TASK) );
actual_delta_ms = (end - start) * 1000.0;
if (fabs(JOBS * PERIOD - actual_delta_ms) > ACCEPTABLE_MARGIN)
fprintf(stderr, "actual_delta_ms:%.4f expected:%.4f\n",
actual_delta_ms, (double) (JOBS * PERIOD));
ASSERT( fabs(JOBS * PERIOD - actual_delta_ms) <= ACCEPTABLE_MARGIN);
);
do {
waiters = get_nr_ts_release_waiters();
ASSERT( waiters >= 0 );
} while (waiters != 1);
waiters = release_ts(&delay);
/* wait for child to exit */
SYSCALL( waitpid(child, &status, 0) );
ASSERT( status == 0 );
}