Programmazione RTAI
E.Mumolo, DEEI
[email protected]
Programmazione in RTAI

Approccio RTAI:





Uno schedulatore Real Time rimpiazza lo schedulatore di Linux
Intercetta gli interrupt (time e dispositivi)
Esegue il codice di servizio degli interrupt in tempo reale
Esegue Linux nel tempo rimanente (background)
Task in tempo reale: moduli di kernel non codice Linux
 ogni errore provoca un crash del kernel
 non hanno accesso a funzioni di I/O (terminale, disco…)
 necessità di una comunicazione kernel/utente per I/O

I MODULI DEL KERNEL SONO CARICATI DINAMICAMENTE!!


insmod
rmmod
Programmazione in RTAI
Codifica in C
Ogni modulo del kernel ha un’entry point (init_module)
e un exit point (cleanup_module)
In definitiva: la struttura utilizza 3 parti principali scritte
dall’utente



1.
2.
3.
Funzione che inizializza il sistema, definisce le caratteristiche
dei vari task e IPC
Definizione della funzione real time
Funzione che rilascia le risorse
Programmazione in RTAI

Esempio della funzione di rilascio risorse
int cleanup_module(void)
{
//ferma il timer
stop_rt_timer();
rt_busy_sleep(10000000);
//chiude la fifo
rtf_destroy(0);
//cancella la struttura rt
rt_task_delete(&hiprio_task);
}
Programmazione in RTAI

Primo esempio:
#include <linux/kernel.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
int init_module(void) //entry point
{
printk("Hello world!\n"); // printk = scrive in /var/log/messages
return 0;
}
void cleanup_module(void) //exit point
{
printk("Goodbye world!\n");
return;
}
Programmazione in RTAI

Compilazione sorgenti:




usare il Makefile del kernel
make –f Makefile –C <kernel path> M=$PWD
Genera il file <modulo.ko>
Nel nostro caso:
EXTRA_CFLAGS += -I/usr/realtime/include -D_IN_RTAI_
obj-m += prog1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


Per eseguire il modulo: insmod <modulo.ko>
Per terminare : rmmod <modulo.ko>
Programmazione in RTAI
Attenzione (1): printk scrive nel ‘kernel ring buffer
Il buffer viene scritto periodicamente sul file di log /var/log/messages
Attenzione (2): printk può non essere predicibile: rt_printk versione RT
Scrive sul kernel Ring buffer. Per leggere/cancellare il buffer: chiamate di
sistema:
syslog, klogctl - read
set console_loglevel
and/or clear kernel message ring buffer;
comandi Linux
$tkadmin dump ringbuffer ringbuffer.out
In definitiva: dmesg –c|insmod hello.ko|dmesg|rmmod
Oppure: tail -f /var/log/messages
hello.ko|dmesg
Programmazione in RTAI

Definizione di un task (thread in tempo reale):
int rt_task_init(RT_TASK *task, void(*rt_thread)(int), int data, int stack_size,
int priority, int uso_fpu, void(*signal)(void));



Attenzione: definisce il task, non l’esegue!
Il task si trova nello stato SUSPENDED
Argomenti della funzione:





Primo argomento: descrittore del task
Secondo argomento: entry point della funzione
Terzo argomento: un intero passato dal genitore al thread
Quarto argomento: dimensione dello stack
Quinto argomento: priorità . Da rtai_sched.h:





#define RT_SCHED_HIGHEST_PRIORITY 0
#define RT_SCHED_LOWEST_PRIORITY 0x3fffFfff
#define RT_SCHED_LINUX_PRIORITY 0x7fffFfff
Sesto argomento: flag per l’uso della fpu
Settimo argomento: funzione per gestire il segnale inviato ogni volta che
il thread diventa running
Programmazione in RTAI

Schedulazione in RTAI: periodica – aperiodica (one-shot)

Modalità di funzionamento:
void rt_set_oneshot_mode(void);//imposta lo schedulatore
I task possono essere eseguiti in istanti qualsiasi
void rt_set_periodic_mode(void); );//imposta lo schedulatore
Ogni richiesta non multiplo del periodo viene soddisfatta nel periodo di base
del timer più vicino. È il default.

La schedulazione è associata al timer:
RTIME start_rt_timer(int period);//se aperiodic il periodo è ignorato
RTIME rt_get_time();//ticks se periodico, TSC se aperiodico
void stop_rt_timer(void);

Esempio:
rt_set_oneshot_mode();
start_rt_timer(1);

RTIME Internal count units; // misura il tempo trascorso in ticks

Tempi: 1 tick=838 ns (timer del PC)
Inoltre: Time Stamp Clock (TSC): clock del PC

Programmazione in RTAI

Attivazione timer:

periodico
void rt_set_periodic_mode(void);
RTIME start_rt_timer(RTIME period);

one-shot
void rt_set_oneshot_mode(void);
RTIME start_rt_timer(RTIME period);

La funzione
RTIME nano2counts(int nanoseconds);
converte da ns a ticks
Programmazione in RTAI

Esecuzione di un task in tempo reale: due modalità

Rende un processo RTAI periodico ed avvia la prima esecuzione all’istante
<start_time>:
int rt_task_make_periodic(RT_TASK *task, RTIME start_time, RTIME period);

Task aperiodico (one shot):

esecuzione immediata
int rt_task_resume(RT_TASK *task);

esecuzione ad un istante assoluto start_time
int rt_task_make_periodic(RT_TASK *task, RTIME start_time, RTIME period);
//period non usato

esecuzione ad un istante relativo start_delay
int rt_task_make_periodic_relative_ns (RT_TASK *task, RTIME start_delay, RTIME
period);
Programmazione in RTAI

In definitiva per creare un task aperiodico:
rt_set_oneshot_mode(); start_rt_timer(1);
retval =rt_task_init(&task, function, 0, 1024, RT_SCHED_LOWEST_PRIORITY, 0, 0);
retval = rt_task_resume(&task);

Gestione della schedulazione:
Nel caso di task periodico
int rt_task_wait_period(void);
sospende l’esecuzione del thread corrente fino al prossimo periodo
 Nel caso di task aperiodico
int rt_task_yield(void);
int rt_task_suspend(RT_TASK *task);
 task_yield Fa assumere al processo chiamante lo stato READY
 task_suspend sospende l’esecuzione, che verrà ripresa con resume o
con make_periodic


Programma d’esempio: crea un task aperiodico
#include <linux/kernel.h>
/* dichiarazioni richieste dai moduli del kernel */
#include <linux/module.h>
/* dichiarazioni richieste dai moduli del kernel */
#include <linux/version.h>
#include <linux/errno.h>
/* EINVAL, ENOMEM */
#include "rtai.h"
#include "rtai_sched.h"
#include <rtai_sem.h>
MODULE_LICENSE("GPL"); static RT_TASK print_task;
void print_function(long arg)
{
rt_printk("Hello world!\n");
return; }
int init_module(void)
{
int retval;
rt_set_oneshot_mode(); start_rt_timer(1); //parte l’esecuzione
retval = /* crea il tread real time */
rt_task_init(&print_task, print_function, 0, 1024, RT_SCHED_LOWEST_PRIORITY, 0, 0);
if ( retval != 0) {
if (-EINVAL == retval) { printk("task: task structure is invalid\n"); }
else {printk("task: error starting task\n");}
return retval;
}
retval = rt_task_resume(&print_task); /* punta alla nostra struttura */
if (0 != retval) {
if (-EINVAL == retval) {printk("struttura task invalida\n");}
else
{ printk("task: error starting task\n"); }
return retval;
}
return 0;
}
void cleanup_module(void)
{ return; }
Programmazione in RTAI

Funzioni di utilità per la schedulazione:
void rt_sleep(RTIME delay);
void rt_sleep_until(RTIME time);
sospendono il thread in esecuzione e lo mettono in stato DELAYED
void rt_busy_sleep(int nanosecs);
addormenta in thread mandando in loop la CPU per il tempo indicato
void rt_sched_lock(void);
void rt_sched_unlock(void);
blocca/sblocca lo schedulatore pe evitare corse critiche
int rt_get_prio(RT_TASK *task);
int rt_change_prio(RT_TASK *task, int priority;
determina/setta la priorità di base
int rt_get_inher_prio(RT_TASK *task);
Determina la priorità ereditata a causa dell’accesso a risorse condivise (protocolli priority
inheritance)
Programmazione in RTAI

Altre funzioni di utilità per la schedulazione:
int rt_get_task_state(RT_TASK *task);
RT_TASK *rt_whoami(void);
int rt_task_use_fpu(RT_TASK *task, int use_fpu_flag);
int rt_task_delete(RT_TASK *task);
rimuove is task dal sistema
Programmazione in RTAI:
Schedulazione periodica

Non c’è particolare limite al numero di task

I task sono thread: condividono lo spazio di indirizzamento!!
Attenzione alla mutua esclusione

Dobbiamo determinare il periodo di base. Il periodo dei thread è un
multiplo del periodo di base

Programma d’esempio:



setto il timer a 1 ms
definisco la funzione
schedulazione
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/io.h>
#include "rtai.h"
#include "rtai_sched.h"
MODULE_LICENSE("GPL");
static RT_TASK sound_task; static RT_TASK delay_task;
static RTIME sound_period_ns = 1e5;
/* in nanoseconds, -> 10 kHz */
static RTIME delay_period_ns = 1e9;
/* in nanoseconds, -> 1 Hz */
#define SOUND_PORT 0x61
/* indrizzo altoparlante */
#define SOUND_MASK 0x02
/* bit da cambiare */
static int delay_count = 2; // condivisa tra i due threa: onda quadra per altoparlante
int init_module(void)
{ RTIME sound_period_count, delay_period_count, timer_period_count;
int retval;
rt_set_periodic_mode();
sound_period_count = nano2count(sound_period_ns);
delay_period_count = nano2count(delay_period_ns);
timer_period_count = start_rt_timer(sound_period_count);
printk("sound task: requested %d counts, got %d counts\n",(int) sound_period_count,
(int) timer_period_count);
retval = //struttura del thread ‘sound’
rt_task_init(&sound_task, sound_function, 0, 1024, RT_LOWEST_PRIORITY - 1, 0, 0);
if (0 != retval) {
if (-EINVAL == retval) {printk("sound task: task structure already in use\n");}
else if (-ENOMEM == retval) {printk("sound task: can't allocate stack\n"); }
else {printk("sound task: error initializing task structure\n"); }
return retval;
}
retval = //struttura del thread ‘delay’
rt_task_init(&delay_task, delay_function, 0, 1024, RT_LOWEST_PRIORITY, 0, 0);
if (0 != retval) { if (-EINVAL == retval) {printk(“errore: gia’ in uso\n"); }
else if (-ENOMEM == retval) {printk(“errore di stack\n"); }
else {printk(“error di inizializzazione\n"); }
return retval;
}
retval = //esegue il thread ‘sund’
rt_task_make_periodic(&sound_task, rt_get_time() + sound_period_count,
sound_period_count);
if (0 != retval) { if (-EINVAL == retval) {printk("sound errore\n"); }
else {printk("sound errore task\n"); }
return retval;
}
retval = //esegue il thread ‘delay’
rt_task_make_periodic(&delay_task, rt_get_time() + delay_period_count,
delay_period_count);
if (0 != retval) { if (-EINVAL == retval) {printk(“errore delay \n"); }
else {printk("delay task: error starting task\n"); }
return retval;
}
return 0;
/* success! */
}
void sound_function(int arg)
{
int delay_left = delay_count;
/* decrementato ad ogni ciclo */
unsigned char sound_byte, toggle = 0;
while (1) {
if (delay_left > 0) { //ritardo restante?
delay_left--;
} else {
sound_byte = inb(SOUND_PORT);
if (toggle) { sound_byte = sound_byte | SOUND_MASK; }
else { sound_byte = sound_byte & ~SOUND_MASK; }
outb(sound_byte, SOUND_PORT);
toggle = ! toggle;
delay_left = delay_count;
/* ricarico il ritardo*/
}
rt_task_wait_period();
}
/* non arriviamo mai qui */
return;
}
void delay_function(int arg)
{ while (1) { delay_count++;
/* non arriviamo mai qui */
return;
}
rt_task_wait_period();
}
void cleanup_module(void)
{
int retval;
retval = rt_task_delete(&sound_task);
if (0 != retval) {
if (-EINVAL == retval) {
/* invalid task structure */
printk("sound task: task structure is invalid\n");
} else {
printk("sound task: error stopping task\n");
}
}
retval = rt_task_delete(&delay_task);
if (0 != retval) {
if (-EINVAL == retval) {
/* invalid task structure */
printk("delay task: task structure is invalid\n");
} else {
printk("delay task: error stopping task\n");
}
}
outb(inb(SOUND_PORT) & ~SOUND_MASK, SOUND_PORT); //toggle il bit
return;
}
Programmazione in RTAI

Politiche di schedulazione


RTAI offre la possibilità di usare le seguenti politiche: FIFO (default), Round
Robin.
Abilitazione delle politiche:
void rt_set_sched_policy(struct rt_task_struct *task,
int policy,
int rr_quantum_ns);

Politiche: RT_SCHED_RR - RT_SCHED_FIFO

Esempio: 3 task: appena creati sono bloccati da un semaforo che viene
aperto appena possono continuare.

Ogni task esegue per EXECTIME unità temporali, realizzato come segue:
starttime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (starttime + EXECTIME));

Vene contato il numero di context switch mediante un semaforo
Programmazione in RTAI

In definitiva, la sched. FIFO si realizza con queste
istruzioni:
…
void func1();
void func2();
int init_module()
{
rt_set_periodic_mode();
rt_task_init(&t1,func1,…);
rt_task_init(&t2,func2,…);
rt_task_make_periodic(&t1,start1,periodo1);
rt_task_make_periodic(&t2,start1,periodo2);
…
}
NB: FIFO può essere facilmente anche RM
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_sem.h>
MODULE_LICENSE("GPL");
#define STACK_SIZE 2000
#define EXECTIME 400000000
#define RR_QUANTUM 10000000
#define NTASKS 3
#define PRIORITY 100
static SEM sync, RT_TASK tasks[NTASKS], int switchesCount[NTASKS];
static void fun(long indx) //funzione eseguita dai task
{
RTIME starttime, endtime;;
rt_printk("Resume task #%d (%p) on CPU %d.\n", indx, &tasks[indx], hard_cpu_id());
rt_sem_wait(&sync);
rt_printk("Task #%d (%p) inizia on CPU %d.\n", indx, &tasks[indx], hard_cpu_id());
starttime = rt_get_cpu_time_ns(); //esegue per EXECTIME
while(rt_get_cpu_time_ns() < (starttime + EXECTIME));
endtime = rt_get_cpu_time_ns()-starttime; //segnala il nr di context switch
tasks[indx].signal = 0;
rt_printk("Task #%d (%p) terminates after %d.\n", indx, &tasks[indx],endtime);
}
static void signal(void) //esegue quando c’e’ un context switch
{
RT_TASK *task;
int i;
for (i = 0; i < NTASKS; i++) {
if ((task = rt_whoami()) == &tasks[i]) {
switchesCount[i]++;
rt_printk("Switch al task #%d (%p) on CPU %d.\n", i, task, hard_cpu_id());
break;
}
}
}
int init_module(void)
{
int i;
printk("INSMOD on CPU %d.\n", hard_cpu_id());
rt_sem_init(&sync, 0);
rt_set_oneshot_mode();
start_rt_timer(1);
}
for (i = 0; i < NTASKS; i++) {
rt_task_init(&tasks[i], fun, i, STACK_SIZE, PRIORITY, 0, signal);
}
for (i = 0; i < NTASKS; i++) {
rt_task_resume(&tasks[i]);
}
rt_sem_broadcast(&sync);
return 0;
void cleanup_module(void)
{
int i;
}
stop_rt_timer();
rt_sem_delete(&sync);
for (i = 0; i < NTASKS; i++) {
printk("nr di context switches task # %d -> %d\n", i, switchesCount[i]);
rt_task_delete(&tasks[i]);
}
Programmazione in RTAI

Schedulazione prioritaria:





I thread hanno una priorità tra 0
(RT_SCHED_HIGHEST_PRIORITY) e 1,073,741,823
(RT_SCHED_LOWEST_PRIORITY )
Quando si crea un task con rt_task_init(..) uno degli argomenti è
la priorità
Dopo che viene eseguito un task può variare priorità con int
rt_change_prio( RT_TASK *task, intpriority) ;
La politica prioritaria è RT_SCHED_FIFO
Esempio: creazione di 3 task a diverse priorità. Provae a
cambiare le priorità
#include <linux/kernel.h>
#include <linux/module.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_sem.h>
MODULE_LICENSE("GPL");
#define STACK_SIZE 2000
#define EXECTIME
400000000
#define RR_QUANTUM 10000000
#define NTASKS 3
#define HIGH 100
#define MID 101
#define LOW 102
static SEM sync, RT_TASK tasks[NTASKS],
int switchesCount[NTASKS];
static void fun(long indx)
{
RTIME starttime, endtime;
rt_printk("Resume task #%d (%p) on CPU %d.\n", indx, &tasks[indx], hard_cpu_id());
rt_sem_wait(&sync);
rt_printk("Task #%d (%p) inizia su CPU %d.\n", indx, &tasks[indx], hard_cpu_id());
starttime = rt_get_cpu_time_ns();
//esegue per EXECTIME
while(rt_get_cpu_time_ns() < (starttime + EXECTIME));
endtime = rt_get_cpu_time_ns()-starttime;
tasks[indx].signal = 0;
rt_printk("Task #%d (%p) terminates after %d.\n", indx, &tasks[indx],endtime);
}
static void signal(void) //per segnalare il nr di context switches
{
RT_TASK *task;
int i;
for (i = 0; i < NTASKS; i++) {
if ((task = rt_whoami()) == &tasks[i]) {
switchesCount[i]++; rt_printk(“passa a #%d (%p) su %d.\n", i, task, hard_cpu_id());
break;
}
}
}
int init_module(void)
{
int i;
printk("INSMOD on CPU %d.\n", hard_cpu_id()); rt_sem_init(&sync, 0);
rt_set_oneshot_mode();
start_rt_timer(1);
rt_task_init(&tasks[0], fun, 0, STACK_SIZE, LOW, 0, signal);
rt_task_init(&tasks[1], fun, 1, STACK_SIZE, MID, 0, signal);
rt_task_init(&tasks[2], fun, 2, STACK_SIZE, HIGH, 0, signal);
for (i = 0; i < NTASKS; i++) {
rt_task_resume(&tasks[i]);
while(!(rt_get_task_state(&tasks[i]) & RT_SCHED_SEMAPHORE));
}
rt_sem_broadcast(&sync);
return 0;
}
void cleanup_module(void)
{
int i;
stop_rt_timer(); rt_sem_delete(&sync);
for (i = 0; i < NTASKS; i++) {
printk("number of context switches task # %d -> %d\n", i, switchesCount[i]);
rt_task_delete(&tasks[i]);
}
}
Programmazione in RTAI

Schedulazione RateMonotonic (RM)
#include <linux/kernel.h>
/* decls needed for kernel modules */
#include <linux/module.h>
/* decls needed for kernel modules */
#include <linux/version.h>
/* LINUX_VERSION_CODE, KERNEL_VERSION() */
#include <linux/errno.h>
/* EINVAL, ENOMEM */
#include "rtai.h"
#include "rtai_sched.h"
#include <rtai_sem.h>
MODULE_LICENSE("GPL");
#define NTASKS 3
#define STACK_SIZE 10000
static RT_TASK tasks[NTASKS];
static int task_arg[NTASKS];
#define BASE_PERIOD_NS 1000000
static RTIME base_period; // in internal units
static RTIME base_period_us; // in microseconds
static RTIME base_period_ns; // in nanoseconds
static int task_computation_time[NTASKS] = { 30 , 20 , 20 }; //timer periodici
static int task_period[NTASKS]
= { 60 , 90 , 110 } ;
static int task_priority[NTASKS]
= { 10 , 20 , 30 } ;
static int ggd=1980; // 6*9*11/3
RTIME resumetime[NTASKS], deadlinetime[NTASKS];
int nodeadlinemiss=1;
static SEM sync;
static RTIME tasks_starttime=0;
static int switchesCount[NTASKS];
#define CALIBRATION_PERCENTAGE 100 //parametro per l’attesa attiva
#define CALIBRATION_LOOP_SIZE 1e7 //più alto (non troppo) più accurato
static RT_TASK init_task_str;
static RTIME count_need_for_one_ms_busysleep;
static int task_period_counter[NTASKS]
= { 0 , 0 , 0 } ;
inline RTIME loop(RTIME count) { //esegue un loop da 0 a count
unsigned long int i;
// ritorna il tempo in ns per eseguire un loop
RTIME starttime, sleeptime_ns;
starttime = rt_get_time_ns();
for (i = 0; i < count ; i++) {} sleeptime_ns=rt_get_time_ns()-starttime; return sleeptime_ns;
}
/* function to callibrate busysleep function */
void calibrate_busysleep(void)
{
RTIME sleeptime_ns;
RTIME x;
volatile RTIME loop_size=CALIBRATION_LOOP_SIZE;
// loop with global CALIBRATION_LOOP_SIZE
sleeptime_ns=loop(loop_size);
rt_printk("sleeptime_ns=%lld\n",sleeptime_ns);
//
//
sleeptime_in_us = sleeptime_ns/1000
//
count_need_for_one_us_busysleep=calibration_loop_size/sleeptime_in_us;
//
-> somma fattore di calibrazione :
//
sleeptime_in_us -> sleeptime_in_us * calibrationpercentage/100
//
-> in definitiva
//
counterbusysleepns= calibration_loop_size*10*calibrationpercentage/sleeptime_ns
x=CALIBRATION_LOOP_SIZE*10*CALIBRATION_PERCENTAGE*1000;
do_div(x,sleeptime_ns);
// fattore di calibrazione ttale
count_need_for_one_ms_busysleep=x;
}
//tiene il processore occuato per sleeptime_us, ritorna il tempo passato
RTIME busysleep(RTIME sleeptime_us ) {
RTIME temp;
RTIME sleeptime_ns;
RTIME sleep_count;
sleep_count= count_need_for_one_ms_busysleep*sleeptime_us;
do_div(sleep_count,1000);
sleeptime_ns=loop(sleep_count);
return sleeptime_ns;
}
// calibrazione della attesa attiva
{
rt_printk("------------------------------------------ init task started\n",arg);
calibrate_busysleep();
rt_printk("count_need_for_one_ms_busysleep=%lld\n", count_need_for_one_ms_busysleep);
rt_printk("------------------------------------------ init task ended\n",arg);
return;
}
// time_in_base_periods=(rt_get_time()-starttime )/base_period
// -> integer part :
RTIME time_int(RTIME temp)
{
do_div(temp,base_period);
return temp;
}
// -> first two digits :
RTIME time_digits(RTIME temp)
{
RTIME rest;
rest=do_div(temp,base_period);
temp=rest*100;
do_div(temp,base_period);
return temp;
}
RTIME get_time() //calcola il tempo di esecuzione
{
RTIME temp;
temp=rt_get_time()-tasks_starttime;
return temp;
}
void print_info(int currenttask,char *msg) {
RTIME now=get_time();
rt_printk("T%d %s - time %3lld.%02lld - computation %3d - period %3d - interval %d-%d
\n",currenttask, msg,
time_int(now),time_digits(now), task_computation_time[currenttask],
task_period[currenttask], task_period_counter[currenttask]*task_period[currenttask],
(task_period_counter[currenttask]+1)*task_period[currenttask]);
}
void dummy_task(long t) /calibrazione
{
RTIME cur_task_sleeptime_ns, cur_task_sleeptime_us, base_periods_passed, cur_task_period;
cur_task_period=task_period[t]*base_period;
cur_task_sleeptime_us=base_period_us*task_computation_time[t];
task_period_counter[t]=0; base_periods_passed=0;
if (!tasks_starttime) tasks_starttime=rt_get_time();
while( time_int(get_time()) < ggd && nodeadlinemiss ) {
resumetime[t]=tasks_starttime + (task_period_counter[t]*cur_task_period);
deadlinetime[t]=resumetime[t]+cur_task_period; print_info(t,"start ");
cur_task_sleeptime_ns=busysleep(cur_task_sleeptime_us);
if ( rt_get_time() >= deadlinetime[t] + base_period ) {
rt_printk("\n\n\n");
rt_printk(" TASK %d missed deadline %d", t, (task_period_counter[t]+1)*task_period[t] );
rt_printk("\n\n\n");
nodeadlinemiss=0;
}
print_info(t,"stop
"); rt_task_wait_period(); task_period_counter[t]++;
}
print_info(t,"ended ");if (nodeadlinemiss) rt_printk("\n\n SCHEDULABILE\n\n ", t);
return;
}
int init_module(void) //parte il task con chedulaione specifica
{
int i;
RTIME temp,starttime;
printk(“inizia init_module\n");
printk("INSMOD on CPU %d.\n", hard_cpu_id());
rt_sem_init(&sync, 0);
rt_set_periodic_mode(); //configura il modo
base_period = start_rt_timer(nano2count(BASE_PERIOD_NS));
rt_printk("base_period : %lld.\n\n",base_period);
base_period_ns=count2nano(base_period);
rt_printk("base_period_ns : %lld.\n\n",base_period_ns);
temp=base_period_ns; do_div(temp,1000); base_period_us=temp;
// base_period_us=count2nano(base_period)/1000;
rt_printk("base_period_us : %lld.\n\n",base_period_us);
rt_task_init(&init_task_str, init, 0, STACK_SIZE, 100, 0, 0);
rt_task_resume(&init_task_str);
for (i = 0; i < NTASKS; i++) {
task_arg[i]=i; // il task fittizio parte subito
rt_task_init(&tasks[i], dummy_task, task_arg[i], STACK_SIZE, task_priority[i], 1, 0);
}
starttime=rt_get_time()+1000000;
for (i = 0; i < NTASKS; i++) {
rt_task_make_periodic(&tasks[i], starttime,task_period[i]*base_period);
}
printk("End of init_module\n");
return 0;
}
void cleanup_module(void)
{
int i;
stop_rt_timer();
rt_sem_delete(&sync);
printk("\n\n");
for (i = 0; i < NTASKS; i++) {
rt_task_delete(&tasks[i]);
}
rt_task_delete(&init_task_str);
}
Schedulazione EarliestDeadlineFirst
(EDF)
#include <linux/module.h>
#include <asm/io.h>
#include <asm/rtai.h>
#include <rtai_sched.h>
#define ONE_SHOT
#define TICK_PERIOD 10000000
#define STACK_SIZE 2000
#define LOOPS 3
#define NTASKS 8
static RT_TASK thread[NTASKS];
static RTIME tick_period;
static int cpu_used[NR_RT_CPUS];
static void fun(long t)
{
unsigned int loops = LOOPS;
while(loops--) {
cpu_used[hard_cpu_id()]++;
rt_printk("TASK %d with priority %d in loop %d \n", t, thread[t].priority,loops);
rt_task_set_resume_end_times(-NTASKS*tick_period, -(t + 1)*tick_period);
}
rt_printk("TASK %d with priority %d ENDS\n", t, thread[t].priority);
}
EDF (cont.)
int init_module(void)
{
RTIME now;
int i;
#ifdef ONE_SHOT
rt_set_oneshot_mode();
#endif
for (i=0;i<NTASKS;i++) rt_task_init(&thread[i],fun,i,STACK_SIZE,NTASKS-i-1,0,0);
tick_period = start_rt_timer(nano2count(TICK_PERIOD));
now = rt_get_time() + NTASKS*tick_period;
for (i = 0; i < NTASKS; i++) {
rt_task_make_periodic(&thread[NTASKS - i - 1], now, NTASKS*tick_period);
}
return 0;
}
void cleanup_module(void)
{
int i, cpuid;
stop_rt_timer();
for (i = 0; i < NTASKS; i++) {rt_task_delete(&thread[i]);}
printk("\n\nCPU USE SUMMARY\n");
for (cpuid = 0; cpuid < NR_RT_CPUS; cpuid++) {
printk("# %d -> %d\n", cpuid, cpu_used[cpuid]);
}
printk("END OF CPU USE SUMMARY\n\n");
}
Programmazione in RTAI: IPC

RTAI usa sistemi di IPC simili a Linux ma implementati
separatamente:
rt_fifo: scambio dati tra i thread in tempo reale, tra processi Linux,
shared memory, tra thread in tempo reale e processi Linux
 mailbox
 semafori
 RPC

Programmazione in RTAI: IPC

rt_fifo

Per creare una rt_fifo:
int rtf_create(unsigned int fifo, int size);
Per dimensionare una rt_fifo:
int rtf_resize(int fd, int size);

Per creare/aprire una rt_fifo dallo spazio utente si usa
file_descriptor = open("/dev/rtf0", O_RDONLY);

Per creare/aprire una rt_fifo dallo spazio kernel si usa:
int rtf_open_sized(const char *dev, int perm, int size);
Le rt_fifo possono essere associate a dei command handler che vanno
in esecuzione ogni volta che un processo nello spazio utente esegue
una read() o una write() sulla fifo:

int rtf_create_handler(unsigned int minor, int (*handler)(unsigned int fifo)););
Programmazione in RTAI: IPC

rt_fifo: esempio d’uso dei command handler
int rtf_create_handler(fifo_numver, X_FIFO_HANDLER(x_handler);
con, ad esempio, come x_handler:
int x_handler(unsigned int fifo, int rw)
{
if(rw==‘r’){
//quello che bisogna fare in relazione ad una read
}
else{
//quello che bisogna fare in relazione ad una write
}
}
Programmazione in RTAI: IPC

rt_fifo: per evitare bloccaggi indeterminati
int rtf_read_all_at_once(int fd, void *buf, int count);
int rtf_read_timed(int fd, void *buf, int count, int ms_delay);
int rtf_write_timed(int fd, void *buf, int count, int ms_delay);

rt_fifo: uso dei semafori
int rtf_sem_init(unsigned int fifo, int value);
int rtf_sem_wait(unsigned int fifo); //solo dallo spazio utente
int rtf_sem_trywait(unsigned int fifo); //solo dallo spazio utente
...
Programmazione in RTAI: IPC

Per accedere una rt_fifo

Dal lato real time
num_read = rtf_get(0, &buffer_in, sizeof(buffer_in));
num_written = rtf_put(1, &buffer_out, sizeof(buffer_out));

Dal lato Linux
num_read = read(read_descriptor, &buffer_in, sizeof(buffer_in));
num_written = write(write_descriptor, &buffer_out,sizeof(buffer_out));

Letture bloccanti: Unix supporta sia lettura bloccanti che non

In sistemi real time sono preferibili le letture non bloccanti: 'rtf_get()'
ritorna immediatamente se non ci sono dati da leggere
//FIFO monodirezionali
#include <linux/kernel.h>
/* decls needed for kernel modules */
#include <linux/module.h>
/* decls needed for kernel modules */
#include <linux/version.h>
/* LINUX_VERSION_CODE, KERNEL_VERSION() */
#include <linux/errno.h> /* EINVAL, ENOMEM */
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>
MODULE_LICENSE("GPL")
;
static RT_TASK t1;
static RT_TASK t2;
void taskOne(long arg);
void taskTwo(long arg);
#define MAX_MESSAGES 100
#define MAX_MESSAGE_LENGTH 50
void message(void) /* function to create the message queue and two tasks */
{
int retval;
rtf_create (0,MAX_MESSAGES*MAX_MESSAGE_LENGTH); //crea una FIFO con numero 0
retval = rt_task_init(&t1,taskOne, 0, 1024, 0, 0, 0);
retval = rt_task_init(&t2,taskTwo, 0, 1024, 0, 0, 0);
retval = rt_task_resume(&t1); //esegue i thread: attenzione all’ordine
retval = rt_task_resume(&t2);
}
void taskOne(long arg)
{
int retval;
char message[] = "Received message from taskOne";
rt_printk("taskOne starts sending message\n");
retval = rtf_put(0, &message, sizeof(message)); //trasmette
rt_printk("taskOne continues after sending message\n");
}
void taskTwo(long arg)
{
int retval;
char msgBuf[MAX_MESSAGE_LENGTH];
rt_printk("taskTwo ready to receive\n");
retval = rtf_get(0, &msgBuf, sizeof(msgBuf));
//riceve
if (retval>0){
rt_printk("TaskTwo: %s\n", msgBuf); rt_printk(" lunghezza: %d\n", retval);
} else { printk("FIFO queue is empty\n"); }
}
int init_module(void)
{
printk("start of init_module\n");
rt_set_oneshot_mode(); start_rt_timer(1);
message();
printk("end of init_module\n");
return 0;
}
void cleanup_module(void)
{ stop_rt_timer(); rt_task_delete(&t1); rt_task_delete(&t2);
return;
}
Altro esempio: FIFO bidirezionali
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>
MODULE_LICENSE("GPL");
static RT_TASK t1;
static RT_TASK t2;
void taskOne(long arg);
void taskTwo(long arg);
#define MAX_MESSAGES 100
#define MAX_MESSAGE_LENGTH 50
static RTIME delay_count, delay_ns = 1e6;
/* in nanoseconds, -> 1 msec */
void message(void) /* function to create the message queue and two tasks */
{
int retval;
rtf_create (1,MAX_MESSAGES*MAX_MESSAGE_LENGTH); //crea FIFO con id 0
rtf_create (2,MAX_MESSAGES*MAX_MESSAGE_LENGTH);
rt_set_oneshot_mode();
start_rt_timer(1);
delay_count = nano2count(delay_ns); //specifica il ritardo
retval = rt_task_init(&t1,taskOne, 0, 1024, 0, 0, 0);
retval = rt_task_init(&t2,taskTwo, 0, 1024, 0, 0, 0);
retval = rt_task_resume(&t1);
retval = rt_task_resume(&t2); //esegue i thread
}
void taskOne(long arg)
{
int retval=0; char message[] = “Messaggio dal taskOne";
char msgBuf[MAX_MESSAGE_LENGTH];
msgBuf[0]=0;
rt_printk("taskOne inizia a mandare un messaggio al taskTwo via FIFO\n");
retval = rtf_put(2, &message, sizeof(message)); //manda messaggio a taskTwo
rt_printk("taskOne continua\n");
t_sleep(delay_count); //aspetta per far partire taskTwo
retval = rtf_get(1, &msgBuf, sizeof(msgBuf)); //riceve il messaggio
if ( retval < 0 ) { rt_printk("problem with fifo \n"); } //test: cambia id in rtf_get
else { rt_printk("taskOne riceve: %s con lunghezza: %d \n", msgBuf, retval); }
}
void taskTwo(long arg)
{
int retval=0; char msgBuf[MAX_MESSAGE_LENGTH];
char message[] = " Messaggio dal taskTwo ";
msgBuf[0]=0;
rt_printk(" taskTwo inizia a mandare un messaggio al taskOne via FIFO\n ");
retval = rtf_put(1, &message, sizeof(message)); //manda messaggio a taskOne
rt_printk("taskTwo continua\n"); rt_printk("taskTwo pronto per ricevere\n");
retval = rtf_get(2, &msgBuf, sizeof(msgBuf)); //riceve
if ( retval < 0 ) { rt_printk("problem with fifo \n"); }
else { rt_printk("taskTwo receive: %s con lunghezza %d\n", msgBuf, retval); }
}
int init_module(void)
{
printk("start of init_module\n");
message();
printk("end of init_module\n");
return 0;
}
void cleanup_module(void)
{
stop_rt_timer();
rt_task_delete(&t1);
rt_task_delete(&t2);
return;
}
Programmazione in RTAI: IPC

Mailbox: è un buffer gestito dal SO per scambio di messaggi tra processi e
task







Invio e ricezione di messaggi:




Possono essere inizializzati per messaggi di lunghezza variabile
Supportano più lettori/scrittori su base prioritaria
Gestione prioritaria: un task che invia può essere interrotto se il task che aspetta
è a priorità più alta
Usabili dallo spazio utente e dallo spazio kernel
Possono sostituire le rt_fifo ma sono più lente
Implementate nello schedulatore di RTAI
Incondizionato
Su un certo numero di byte
Con scadenza relativa/assoluta
Per inizializzare/creare (messaggi di lunghezza arbitraria)
int rt_mbx_init(MBX *mbx, int size);//size del buffer

Inizializzare/creare una mailbox tipizzata
int rt_typed_mbx_init(MBX *mbx, int size, int type)
Programmazione in RTAI: IPC

Mailbox: per inviare/ricevere dati senza/con condizioni
int rt_mbx_send(MBX *mbx, int size);
int rt_mbx_receive(MBX *mbx, int size);
int rt_mbx_send_wp(MBX *mbx, int size);
int rt_mbx_receive_wp(MBX *mbx, int size);
int rt_mbx_send_if(MBX *mbx, int size);
int rt_mbx_receive_if(MBX *mbx, int size);

Programma d’esempio: taskOne manda un messaggio via mailbox
a taskTwo che lo scrive
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_mbx.h>
MODULE_LICENSE("GPL");
static RT_TASK t1;
static RT_TASK t2;
void taskOne(long arg);
void taskTwo(long arg);
#define MAX_MESSAGES 100
#define MAX_MESSAGE_LENGTH 50
static MBX mailboxId;
void message(void) /* function
{
int retval;
retval = rt_typed_mbx_init
if (0 != retval) {
if (-ENOMEM == retval)
else { printk(“errore
}
/*
/*
/*
/*
decls needed for kernel modules */
decls needed for kernel modules */
LINUX_VERSION_CODE, KERNEL_VERSION() */
EINVAL, ENOMEM */
to create the message queue and two tasks */
(&mailboxId, MAX_MESSAGES,
FIFO_Q); //crea mailbox
{ printk(“errore ENOMEM"); }
sconosciuto\n"); }
retval = rt_task_init(&t1,taskOne, 0, 1024, 0, 0, 0);
retval = rt_task_init(&t2,taskTwo, 0, 1024, 0, 0, 0); //init
retval = rt_task_resume(&t1); retval = rt_task_resume(&t2); //exec
}
void taskOne(long arg) /* task che scrive nella mailbox */
{
int retval;
char message[] = “ricvuto messaggio da TaskOne";
retval = rt_mbx_send(&mailboxId, message, sizeof(message)); //spedisce
if (0 != retval) {
if (-EINVAL == retval) { rt_printk("mailbox invalida\n"); }
else { rt_printk(“errore sconosciuto\n"); }
} else { rt_printk("taskOne ha inviato messaggio\n");}
}
void taskTwo(long arg) /* tasks che legge dalla mailbox */
{
int retval;
char msgBuf[MAX_MESSAGE_LENGTH];
retval = rt_mbx_receive_wp(&mailboxId, msgBuf, 50);
if (-EINVAL == retval) {
rt_printk("mailbox invalida\n"); }
else {
rt_printk("taskTwo receive : %s con lunghezza %d\n",msgBuf, 50-retval);
}
/* cancella la mailbox */
rt_mbx_delete(&mailboxId);
}
int init_module(void)
{
printk(“inizia init_module\n");
rt_set_oneshot_mode();
start_rt_timer(1);
message();
printk(“finisce init_module\n");
return 0;
}
void cleanup_module(void)
{
stop_rt_timer();
rt_task_delete(&t1);
rt_task_delete(&t2);
return;
}
Programmazione in RTAI: IPC

IPC memoria condivisa (shared memory)



Per trasferire dati tra processi e task
Naturalmente sono molto veloci
Svantaggi:





non essendo serializzati necessitano di un protocollo di accesso
il bloccaggio tra processi e task non è supportato  bisogna gestire il
trasferimento con un metodo
non è garantita la mutua esclusione processi/task
Non è possibile rilevare letture/scritture interrotte
Tipi di shared memory:


Mbuff: condivisione processi/thread (cioè spazio utente/spazio kernel) senza
richiedere RTAI
Shmem: condivisione processi/thread (cioè spazio utente/spaziokernel) che
dipende profondamente da RTAI
Programmazione in RTAI: IPC

mbuff:


Implementata come device driver: device /dev/mbuff
Per accedere alla memoria condivisa dallo spazio utente/kernel:
void *mbuff_alloc(unsigned long name, unsigned int size);
Per rilasciare la memoria:
void mbuf_free(int name, void *mbuf);
IPC in RTAI: memoria condivisa

shmem:


Implementata come device driver: device /dev/rtai_shm
Per accedere dallo spazio utente:
void *rtai_malloc(unsigned long name, int size);

Per rilasciarla:
void rtai_free(int name, void *adr);

Per accedere dallo spazio kernel:
void *rtai_malloc(unsigned long name, int size);

Per rilasciarla:
void rtai_free(int name, void *adr);
IPC in RTAI: semafori

Semafori: sono di tre tipi




Counting: Usati per registrare eventi (CNT_SEM)
Binary: Usati per gestire eventi binari (BIN_SEM)
Resource: Usati per gestire l’accesso a risorse mediante la priority inheritance
(RES_SEM)
Per inizializzare un semaforo:
void rt_typed_sem_init(SEM *sem, int value, int type);

Per usare un semaforo:
int rt_sem_wait(SEM *sem);
int rt_sem_signal(SEM *sem);

Per il test sulla condizione di blocco:
int rt_sem_wait_if(SEM *sem);

Per il test sul tempo massimo di blocco:
int rt_sem_wait_timed(SEM *sem, RTIME delay);
Programmazione in RTAI

Problema della ‘Inversione della priorità’
#include <linux/kernel.h>
/* decls needed for kernel modules */
#include <linux/module.h>
/* decls needed for kernel modules */
#include <linux/version.h>
/* LINUX_VERSION_CODE, KERNEL_VERSION() */
#include <linux/errno.h>
/* EINVAL, ENOMEM */
#include "rtai.h"
/* RTAI configuration switches */
#include "rtai_sched.h“
#include <rtai_sem.h>
MODULE_LICENSE("GPL");
#define ITER 10
#define HIGH 102 /* high priority */
#define MEDIUM 103 /* medium priority */
#define LOW 104 /* low priority */
#define NORMAL_TIME 20000000 /* nanoseconds */
#define LONG_TIME
50000000 /* nanoseconds */
static RT_TASK t1, t2, t3;
void prioHigh(long arg);
void prioMedium(long arg);
void prioLow(long arg);
static SEM sync, SEM semBinary; int global = 0;
void binary(void)
{
int retval;
rt_sem_init(&sync, 0);
rt_typed_sem_init(&semBinary, 1, BIN_SEM | FIFO_Q );
retval = rt_task_init(&t1,prioHigh , 1, 1024, HIGH , 0, 0);
retval = rt_task_init(&t2,prioMedium, 2, 1024, MEDIUM, 0, 0);
retval = rt_task_init(&t3,prioLow
, 3, 1024, LOW
, 0, 0);
retval = rt_task_resume(&t1); retval = rt_task_resume(&t2); retval = rt_task_resume(&t3);
while(!(rt_get_task_state(&t1) & RT_SCHED_SEMAPHORE));
while(!(rt_get_task_state(&t2) & RT_SCHED_SEMAPHORE));
while(!(rt_get_task_state(&t3) & RT_SCHED_SEMAPHORE));
rt_sem_broadcast(&sync);
}
int init_module(void)
{
printk("start of init_module\n");
rt_set_oneshot_mode();
start_rt_timer(1);
binary();
printk("end of init_module\n");
return 0;
}
void cleanup_module(void)
{
return;
}
void prioLow(long arg)
{
RTIME startime;
int i;
rt_printk("RESUMED TASK #%d (%p) ON CPU %d.\n", arg, &t3, hard_cpu_id());
rt_sem_wait(&sync);
for (i=0; i < ITER; i++)
{
rt_sem_wait(&semBinary);/* wait indefinitely for semaphore */
rt_printk("Low priority task locks semaphore\n");
startime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME));
rt_printk("Low priority task starts unlock semaphore\n");
rt_sem_signal(&semBinary); /* give up semaphore */
rt_printk("Low priority task has unlocked semaphore\n");
}
rt_printk("..........................................Low priority task exited\n");
}
void prioMedium(long arg)
{
RTIME startime;
int i;
rt_printk("RESUMED TASK #%d (%p) ON CPU %d.\n", arg, &t2, hard_cpu_id());
rt_sem_wait(&sync);
rt_sleep(nano2count(10000000));/* lascia tempo per i thread a bassa priorità */
for (i=0; i < ITER; i++)
{
rt_printk("Medium task running\n"); startime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (startime + LONG_TIME));
}
rt_printk("------------------------------Medium priority task exited\n");
}
void prioHigh(long arg)
{
RTIME startime;
int i;
rt_printk("RESUMED TASK #%d (%p) ON CPU %d.\n", arg, &t1, hard_cpu_id());
rt_sem_wait(&sync);
rt_sleep(nano2count(30000000));/* lascia tempo */
for (i=0; i < ITER; i++)
{
rt_printk("High priority task trys to lock semaphore\n");
rt_sem_wait(&semBinary);/* wait indefinitely for semaphore */
rt_printk("High priority task locks semaphore\n");
startime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME));
rt_sem_signal(&semBinary); /* give up semaphore */
rt_printk("High priority task unlocks semaphore\n");
}
rt_printk("...............................High priority task exited\n");
}
Programmazione in RTAI

Algoritmo priority inversion –
implementazione in RTAI
–
Si risolve con semafori di tipo resource:
rt_typed_sem_init(&semBinary, 1, BIN_SEM | FIFO_Q );
#include <linux/kernel.h>
/* decls needed for kernel modules */
#include <linux/module.h>
/* decls needed for kernel modules */
#include <linux/version.h>
/* LINUX_VERSION_CODE, KERNEL_VERSION() */
#include <linux/errno.h>
/* EINVAL, ENOMEM */
#include "rtai.h"
/* RTAI configuration switches */
#include "rtai_sched.h"
#include <rtai_sem.h>
MODULE_LICENSE("GPL");
#define ITER 10
#define HIGH 102 /* high priority */
#define MEDIUM 103 /* medium priority */
#define LOW 104 /* low priority */
#define NORMAL_TIME 20000000 /* nanoseconds */
#define LONG_TIME
50000000 /* nanoseconds */
static RT_TASK t1, t2, t3;
void prioHigh(long arg);
void prioMedium(long arg);
void prioLow(long arg);
static SEM sync, SEM semBinary;; // semafori
int global = 0;
void binary(void)
{
int retval;
rt_sem_init(&sync, 0);
rt_typed_sem_init(&semBinary, 1, RES_SEM | FIFO_Q );
retval = rt_task_init(&t1,prioHigh , 1, 1024, HIGH , 0, 0);
retval = rt_task_init(&t2,prioMedium, 2, 1024, MEDIUM, 0, 0);
retval = rt_task_init(&t3,prioLow
, 3, 1024, LOW
, 0, 0);
retval = rt_task_resume(&t1);retval = rt_task_resume(&t2);retval = rt_task_resume(&t3);
while(!(rt_get_task_state(&t1) & RT_SCHED_SEMAPHORE));
while(!(rt_get_task_state(&t2) & RT_SCHED_SEMAPHORE));
while(!(rt_get_task_state(&t3) & RT_SCHED_SEMAPHORE));
rt_sem_broadcast(&sync);
}
void prioLow(long arg)
{
RTIME startime;
int i;
rt_printk("RESUMED TASK #%d (%p) ON CPU %d.\n", arg, &t3, hard_cpu_id());
rt_sem_wait(&sync);
for (i=0; i < ITER; i++)
{
rt_sem_wait(&semBinary);/* wait indefinitely for semaphore */
rt_printk("Low priority task locks semaphore\n");
startime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME));
rt_printk("Low priority task unlocks semaphore\n");
rt_sem_signal(&semBinary); /* give up semaphore */
}
rt_printk("..........................................Low priority task exited\n");
}
void prioMedium(long arg)
{
RTIME startime;
int i;
rt_printk("RESUMED TASK #%d (%p) ON CPU %d.\n", arg, &t2, hard_cpu_id());
rt_sem_wait(&sync);
rt_sleep(nano2count(20000000));/* allow time for task with the lowest priority to seize
semaphore */
for (i=0; i < ITER; i++)
{
rt_printk("Medium task running\n");
startime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (startime + LONG_TIME));
}
rt_printk("------------------------------------------Medium priority task exited\n");
}
void prioHigh(long arg)
{
RTIME startime;
int i;
rt_printk("RESUMED TASK #%d (%p) ON CPU %d.\n", arg, &t1, hard_cpu_id());
rt_sem_wait(&sync);
rt_sleep(nano2count(30000000));/* lascia tempo ai task di piu’ bassa priorità */
for (i=0; i < ITER; i++)
{
rt_printk("High priority task trys to lock semaphore\n");
rt_sem_wait(&semBinary);/* wait indefinitely for semaphore */
rt_printk("High priority task locks semaphore\n");
startime = rt_get_cpu_time_ns();
while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME));
rt_printk("High priority task unlocks semaphore\n");
rt_sem_signal(&semBinary); /* give up semaphore */
}
rt_printk("......................................High priority task exited\n");
}
int init_module(void)
{
printk(“inizia init_module\n");
rt_set_oneshot_mode();
start_rt_timer(1);
binary();
printk("end of init_module\n");
return 0;
}
void cleanup_module(void)
{
return;
}
Scarica

Programmazione RTAI