programmazione rtai

63
Programmazione RTAI E.Mumolo, DEEI [email protected]

Upload: joie

Post on 01-Feb-2016

60 views

Category:

Documents


0 download

DESCRIPTION

E.Mumolo, DEEI [email protected]. Programmazione RTAI. 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 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Programmazione RTAI

Programmazione RTAI

E.Mumolo, DEEI

[email protected]

Page 2: Programmazione RTAI

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

Page 3: Programmazione RTAI

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’utente1. Funzione che inizializza il sistema, definisce le caratteristiche

dei vari task e IPC

2. Definizione della funzione real time

3. Funzione che rilascia le risorse

Page 4: Programmazione RTAI

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);

}

Page 5: Programmazione RTAI

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;

}

Page 6: Programmazione RTAI

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>

Page 7: Programmazione RTAI

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 and/or clear kernel message ring buffer; set console_loglevel

comandi Linux$tkadmin dump ringbuffer ringbuffer.out In definitiva: dmesg –c|insmod hello.ko|dmesg|rmmod hello.ko|dmesgOppure: tail -f /var/log/messages

Page 8: Programmazione RTAI

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

Page 9: Programmazione RTAI

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 qualsiasivoid 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 è ignoratoRTIME rt_get_time();//ticks se periodico, TSC se aperiodicovoid 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

Page 10: Programmazione RTAI

Programmazione in RTAI

Attivazione timer: periodicovoid 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

Page 11: Programmazione RTAI

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_timeint 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);

Page 12: Programmazione RTAI

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

Page 13: Programmazione RTAI

#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’esecuzioneretval = /* 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; }

Page 14: Programmazione RTAI

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)

Page 15: Programmazione RTAI

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

Page 16: Programmazione RTAI

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

Page 17: Programmazione RTAI

#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 altoparlanteint 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; }

Page 18: Programmazione RTAI

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! */}

Page 19: Programmazione RTAI

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++; rt_task_wait_period(); }

/* non arriviamo mai qui */ return;}

Page 20: Programmazione RTAI

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;}

Page 21: Programmazione RTAI

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

Page 22: Programmazione RTAI

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

Page 23: Programmazione RTAI

#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 100static 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 EXECTIMEwhile(rt_get_cpu_time_ns() < (starttime + EXECTIME));endtime = rt_get_cpu_time_ns()-starttime; //segnala il nr di context switchtasks[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; }}

}

Page 24: Programmazione RTAI

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]);}

}

Page 25: Programmazione RTAI

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à

Page 26: Programmazione RTAI

#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 102static 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 EXECTIMEwhile(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);

}

Page 27: Programmazione RTAI

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]);

}}

Page 28: Programmazione RTAI

Programmazione in RTAI

Schedulazione RateMonotonic (RM)

Page 29: Programmazione RTAI

#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 10000static RT_TASK tasks[NTASKS];static int task_arg[NTASKS];#define BASE_PERIOD_NS 1000000static RTIME base_period; // in internal unitsstatic RTIME base_period_us; // in microsecondsstatic RTIME base_period_ns; // in nanosecondsstatic int task_computation_time[NTASKS] = { 30 , 20 , 20 }; //timer periodicistatic int task_period[NTASKS] = { 60 , 90 , 110 } ; static int task_priority[NTASKS] = { 10 , 20 , 30 } ;static int ggd=1980; // 6*9*11/3RTIME 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ù accuratostatic 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;}

Page 30: Programmazione RTAI

/* 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;

}

Page 31: Programmazione RTAI

//tiene il processore occuato per sleeptime_us, ritorna il tempo passatoRTIME 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;}

Page 32: Programmazione RTAI

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;}

Page 33: Programmazione RTAI

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;}

Page 34: Programmazione RTAI

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);}

Page 35: Programmazione RTAI

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 8static 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);}

Page 36: Programmazione RTAI

EDF (cont.)int init_module(void){

RTIME now;int i;

#ifdef ONE_SHOTrt_set_oneshot_mode();

#endiffor (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");

}

Page 37: Programmazione RTAI

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

Page 38: Programmazione RTAI

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)););

Page 39: Programmazione RTAI

Programmazione in RTAI: IPC

rt_fifo: esempio d’uso dei command handlerint 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}

}

Page 40: Programmazione RTAI

Programmazione in RTAI: IPC rt_fifo: per evitare bloccaggi indeterminatiint 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

...

Page 41: Programmazione RTAI

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 Linuxnum_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

Page 42: Programmazione RTAI

//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);}

Page 43: Programmazione RTAI

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; }

Page 44: Programmazione RTAI

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 50static 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}

Page 45: Programmazione RTAI

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); } }

Page 46: Programmazione RTAI

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;}

Page 47: Programmazione RTAI

Programmazione in RTAI: IPC Mailbox: è un buffer gestito dal SO per scambio di messaggi tra processi e

task 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

Invio e ricezione di messaggi: 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 tipizzataint rt_typed_mbx_init(MBX *mbx, int size, int type)

Page 48: Programmazione RTAI

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

Page 49: Programmazione RTAI

#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_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 50static MBX mailboxId;

void message(void) /* function to create the message queue and two tasks */{ int retval;

retval = rt_typed_mbx_init (&mailboxId, MAX_MESSAGES, FIFO_Q); //crea mailbox if (0 != retval) { if (-ENOMEM == retval) { printk(“errore ENOMEM"); }

else { printk(“errore 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}

Page 50: Programmazione RTAI

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);}

Page 51: Programmazione RTAI

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;}

Page 52: Programmazione RTAI

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

Page 53: Programmazione 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);

Page 54: Programmazione RTAI

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);

Page 55: Programmazione RTAI

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);

Page 56: Programmazione RTAI

Programmazione in RTAI

Problema della ‘Inversione della priorità’

Page 57: Programmazione RTAI

#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);}

Page 58: Programmazione RTAI

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");}

Page 59: Programmazione RTAI

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");}

Page 60: Programmazione RTAI

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 );

Page 61: Programmazione RTAI

#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);}

Page 62: Programmazione RTAI

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");}

Page 63: Programmazione RTAI

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;}