Programmazione RTAI E Mumolo DEEI mumolounits it Programmazione

  • Slides: 63
Download presentation
Programmazione RTAI E. Mumolo, DEEI mumolo@units. it

Programmazione RTAI E. Mumolo, DEEI mumolo@units. it

Programmazione in RTAI Approccio RTAI: Uno schedulatore Real Time rimpiazza lo schedulatore di Linux

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)

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

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)

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

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 += prog 1. 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

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. 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,

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 0 x 3 fff. Ffff #define RT_SCHED_LINUX_PRIORITY 0 x 7 fff. Ffff 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

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

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 nano 2 counts(int nanoseconds); converte da ns a ticks

Programmazione in RTAI Esecuzione di un task in tempo reale: due modalità Rende un

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,

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>

#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 invalidn"); } else {printk("task: error starting taskn"); } return retval; } retval = rt_task_resume(&print_task); /* punta alla nostra struttura */ if (0 != retval) { if (-EINVAL == retval) {printk("struttura task invalidan"); } else { printk("task: error starting taskn"); } 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

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

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

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.

#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 = 1 e 5; /* in nanoseconds, -> 10 k. Hz */ static RTIME delay_period_ns = 1 e 9; /* in nanoseconds, -> 1 Hz */ #define SOUND_PORT 0 x 61 /* indrizzo altoparlante */ #define SOUND_MASK 0 x 02 /* 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 = nano 2 count(sound_period_ns); delay_period_count = nano 2 count(delay_period_ns); timer_period_count = start_rt_timer(sound_period_count); printk("sound task: requested %d counts, got %d countsn", (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 usen"); } else if (-ENOMEM == retval) {printk("sound task: can't allocate stackn"); } else {printk("sound task: error initializing task structuren"); } return retval; }

retval = //struttura del thread ‘delay’ rt_task_init(&delay_task, delay_function, 0, 1024, RT_LOWEST_PRIORITY, 0, 0); if

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 uson"); } else if (-ENOMEM == retval) {printk(“errore di stackn"); } else {printk(“error di inizializzazionen"); } 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 erroren"); } else {printk("sound errore taskn"); } 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 taskn"); } return retval; } return 0; /* success! */ }

void sound_function(int arg) { int delay_left = delay_count; /* decrementato ad ogni ciclo */

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

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 invalidn"); } else { printk("sound task: error stopping taskn"); } } retval = rt_task_delete(&delay_task); if (0 != retval) { if (-EINVAL == retval) { /* invalid task structure */ printk("delay task: task structure is invalidn"); } else { printk("delay task: error stopping taskn"); } } 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

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: Vene contato il numero di context switch mediante un semaforo starttime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (starttime + EXECTIME));

Programmazione in RTAI In definitiva, la sched. FIFO si realizza con queste istruzioni: …

Programmazione in RTAI In definitiva, la sched. FIFO si realizza con queste istruzioni: … void func 1(); void func 2(); int init_module() { rt_set_periodic_mode(); rt_task_init(&t 1, func 1, …); rt_task_init(&t 2, func 2, …); rt_task_make_periodic(&t 1, start 1, periodo 1); rt_task_make_periodic(&t 2, start 1, periodo 2); … } NB: FIFO può essere facilmente anche RM

#include <linux/kernel. h> #include <linux/module. h> #include <rtai_sched. h> #include <rtai_sem. h> MODULE_LICENSE("GPL"); #define

#include <linux/kernel. h> #include <linux/module. h> #include <rtai_sched. h> #include <rtai_sem. h> MODULE_LICENSE("GPL"); #define STACK_SIZE 2000 #define EXECTIME 40000 #define RR_QUANTUM 10000000 #define NTASKS 3 #define PRIORITY 100 static SEM sync, RT_TASK tasks[NTASKS], int switches. Count[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]) { switches. Count[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();

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 -> %dn", i, switches. Count[i]); rt_task_delete(&tasks[i]); }

Programmazione in RTAI Schedulazione prioritaria: I thread hanno una priorità tra 0 (RT_SCHED_HIGHEST_PRIORITY) e

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_sched. h> #include <rtai_sem. h> MODULE_LICENSE("GPL"); #define

#include <linux/kernel. h> #include <linux/module. h> #include <rtai_sched. h> #include <rtai_sem. h> MODULE_LICENSE("GPL"); #define STACK_SIZE 2000 #define EXECTIME 40000 #define RR_QUANTUM 10000000 #define NTASKS 3 #define HIGH 100 #define MID 101 #define LOW 102 static SEM sync, RT_TASK tasks[NTASKS], int switches. Count[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

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]) { switches. Count[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 -> %dn", i, switches. Count[i]); rt_task_delete(&tasks[i]); } }

Programmazione in RTAI Schedulazione Rate. Monotonic (RM)

Programmazione in RTAI Schedulazione Rate. Monotonic (RM)

#include <linux/kernel. h> /* decls needed for kernel modules */ #include <linux/module. h> /*

#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 }; //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 switches. Count[NTASKS]; #define CALIBRATION_PERCENTAGE 100 //parametro per l’attesa attiva #define CALIBRATION_LOOP_SIZE 1 e 7 //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 } ; 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;

/* 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=%lldn", 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 )

//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 startedn", arg); calibrate_busysleep(); rt_printk("count_need_for_one_ms_busysleep=%lldn", count_need_for_one_ms_busysleep); rt_printk("--------------------- init task endedn", 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; }

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 %3 lld. %02 lld - computation %3 d - period %3 d - interval %d-%d n", currenttask, msg, time_int(now), time_digits(now), task_computation_time[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("nnn"); rt_printk(" TASK %d missed deadline %d", t, (task_period_counter[t]+1)*task_period[t] ); rt_printk("nnn"); nodeadlinemiss=0; } print_info(t, "stop "); rt_task_wait_period(); task_period_counter[t]++; } print_info(t, "ended "); if (nodeadlinemiss) rt_printk("nn SCHEDULABILEnn ", t); return; }

int init_module(void) //parte il task con chedulaione specifica { int i; RTIME temp, starttime;

int init_module(void) //parte il task con chedulaione specifica { int i; RTIME temp, starttime; printk(“inizia init_modulen"); 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(nano 2 count(BASE_PERIOD_NS)); rt_printk("base_period : %lld. nn", base_period); base_period_ns=count 2 nano(base_period); rt_printk("base_period_ns : %lld. nn", base_period_ns); temp=base_period_ns; do_div(temp, 1000); base_period_us=temp; // base_period_us=count 2 nano(base_period)/1000; rt_printk("base_period_us : %lld. nn", 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_modulen"); return 0; }

void cleanup_module(void) { int i; stop_rt_timer(); rt_sem_delete(&sync); printk("nn"); for (i = 0; i <

void cleanup_module(void) { int i; stop_rt_timer(); rt_sem_delete(&sync); printk("nn"); for (i = 0; i < NTASKS; i++) { rt_task_delete(&tasks[i]); } rt_task_delete(&init_task_str); }

Schedulazione Earliest. Deadline. First (EDF) #include <linux/module. h> #include <asm/io. h> #include <asm/rtai. h>

Schedulazione Earliest. Deadline. First (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 ENDSn", t, thread[t]. priority); }

EDF (cont. ) int init_module(void) { RTIME now; int i; #ifdef ONE_SHOT rt_set_oneshot_mode(); #endif

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(nano 2 count(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("nn. CPU USE SUMMARYn"); for (cpuid = 0; cpuid < NR_RT_CPUS; cpuid++) { printk("# %d -> %dn", cpuid, cpu_used[cpuid]); } printk("END OF CPU USE SUMMARYnn"); }

Programmazione in RTAI: IPC RTAI usa sistemi di IPC simili a Linux ma implementati

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

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/rtf 0", 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,

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,

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 =

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.

//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 t 1; static RT_TASK t 2; void task. One(long arg); void task. Two(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(&t 1, task. One, 0, 1024, 0, 0, 0); retval = rt_task_init(&t 2, task. Two, 0, 1024, 0, 0, 0); retval = rt_task_resume(&t 1); //esegue i thread: attenzione all’ordine retval = rt_task_resume(&t 2); }

void task. One(long arg) { int retval; char message[] = "Received message from task.

void task. One(long arg) { int retval; char message[] = "Received message from task. One"; rt_printk("task. One starts sending messagen"); retval = rtf_put(0, &message, sizeof(message)); //trasmette rt_printk("task. One continues after sending messagen"); } void task. Two(long arg) { int retval; char msg. Buf[MAX_MESSAGE_LENGTH]; rt_printk("task. Two ready to receiven"); retval = rtf_get(0, &msg. Buf, sizeof(msg. Buf)); //riceve if (retval>0){ rt_printk("Task. Two: %sn", msg. Buf); rt_printk(" lunghezza: %dn", retval); } else { printk("FIFO queue is emptyn"); } } int init_module(void) { printk("start of init_modulen"); rt_set_oneshot_mode(); start_rt_timer(1); message(); printk("end of init_modulen"); return 0; } void cleanup_module(void) { stop_rt_timer(); rt_task_delete(&t 1); rt_task_delete(&t 2); return; }

Altro esempio: FIFO bidirezionali #include <linux/kernel. h> #include <linux/module. h> #include <linux/version. h> #include

Altro esempio: FIFO bidirezionali #include <linux/kernel. h> #include <linux/module. h> #include <linux/version. h> #include <linux/errno. h> #include <rtai_sched. h> #include <rtai_fifos. h> MODULE_LICENSE("GPL"); static RT_TASK t 1; static RT_TASK t 2; void task. One(long arg); void task. Two(long arg); #define MAX_MESSAGES 100 #define MAX_MESSAGE_LENGTH 50 static RTIME delay_count, delay_ns = 1 e 6; /* 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 = nano 2 count(delay_ns); //specifica il ritardo retval = rt_task_init(&t 1, task. One, 0, 1024, 0, 0, 0); retval = rt_task_init(&t 2, task. Two, 0, 1024, 0, 0, 0); retval = rt_task_resume(&t 1); retval = rt_task_resume(&t 2); //esegue i thread }

void task. One(long arg) { int retval=0; char message[] = “Messaggio dal task. One";

void task. One(long arg) { int retval=0; char message[] = “Messaggio dal task. One"; char msg. Buf[MAX_MESSAGE_LENGTH]; msg. Buf[0]=0; rt_printk("task. One inizia a mandare un messaggio al task. Two via FIFOn"); retval = rtf_put(2, &message, sizeof(message)); //manda messaggio a task. Two rt_printk("task. One continuan"); t_sleep(delay_count); //aspetta per far partire task. Two retval = rtf_get(1, &msg. Buf, sizeof(msg. Buf)); //riceve il messaggio if ( retval < 0 ) { rt_printk("problem with fifo n"); } //test: cambia id in rtf_get else { rt_printk("task. One riceve: %s con lunghezza: %d n", msg. Buf, retval); } } void task. Two(long arg) { int retval=0; char msg. Buf[MAX_MESSAGE_LENGTH]; char message[] = " Messaggio dal task. Two "; msg. Buf[0]=0; rt_printk(" task. Two inizia a mandare un messaggio al task. One via FIFOn "); retval = rtf_put(1, &message, sizeof(message)); //manda messaggio a task. One rt_printk("task. Two continuan"); rt_printk("task. Two pronto per riceveren"); retval = rtf_get(2, &msg. Buf, sizeof(msg. Buf)); //riceve if ( retval < 0 ) { rt_printk("problem with fifo n"); } else { rt_printk("task. Two receive: %s con lunghezza %dn", msg. Buf, retval); } }

int init_module(void) { printk("start of init_modulen"); message(); printk("end of init_modulen"); return 0; } void

int init_module(void) { printk("start of init_modulen"); message(); printk("end of init_modulen"); return 0; } void cleanup_module(void) { stop_rt_timer(); rt_task_delete(&t 1); rt_task_delete(&t 2); return; }

Programmazione in RTAI: IPC Mailbox: è un buffer gestito dal SO per scambio di

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

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: task. One manda un messaggio via mailbox a task. Two che lo scrive

#include <linux/kernel. h> #include <linux/module. h> #include <linux/version. h> #include <linux/errno. h> #include <rtai_sched.

#include <linux/kernel. h> #include <linux/module. h> #include <linux/version. h> #include <linux/errno. h> #include <rtai_sched. h> #include <rtai_mbx. h> MODULE_LICENSE("GPL"); static RT_TASK t 1; static RT_TASK t 2; void task. One(long arg); void task. Two(long arg); #define MAX_MESSAGES 100 #define MAX_MESSAGE_LENGTH 50 static MBX mailbox. Id; 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 */ LINUX_VERSION_CODE, KERNEL_VERSION() */ EINVAL, ENOMEM */ to create the message queue and two tasks */ (&mailbox. Id, MAX_MESSAGES, FIFO_Q); //crea mailbox { printk(“errore ENOMEM"); } sconosciuton"); } retval = rt_task_init(&t 1, task. One, 0, 1024, 0, 0, 0); retval = rt_task_init(&t 2, task. Two, 0, 1024, 0, 0, 0); //init retval = rt_task_resume(&t 1); retval = rt_task_resume(&t 2); //exec }

void task. One(long arg) /* task che scrive nella mailbox */ { int retval;

void task. One(long arg) /* task che scrive nella mailbox */ { int retval; char message[] = “ricvuto messaggio da Task. One"; retval = rt_mbx_send(&mailbox. Id, message, sizeof(message)); //spedisce if (0 != retval) { if (-EINVAL == retval) { rt_printk("mailbox invalidan"); } else { rt_printk(“errore sconosciuton"); } } else { rt_printk("task. One ha inviato messaggion"); } } void task. Two(long arg) /* tasks che legge dalla mailbox */ { int retval; char msg. Buf[MAX_MESSAGE_LENGTH]; retval = rt_mbx_receive_wp(&mailbox. Id, msg. Buf, 50); if (-EINVAL == retval) { rt_printk("mailbox invalidan"); } else { rt_printk("task. Two receive : %s con lunghezza %dn", msg. Buf, 50 -retval); } /* cancella la mailbox */ rt_mbx_delete(&mailbox. Id); }

int init_module(void) { printk(“inizia init_modulen"); rt_set_oneshot_mode(); start_rt_timer(1); message(); printk(“finisce init_modulen"); return 0; } void

int init_module(void) { printk(“inizia init_modulen"); rt_set_oneshot_mode(); start_rt_timer(1); message(); printk(“finisce init_modulen"); return 0; } void cleanup_module(void) { stop_rt_timer(); rt_task_delete(&t 1); rt_task_delete(&t 2); return; }

Programmazione in RTAI: IPC memoria condivisa (shared memory) Per trasferire dati tra processi e

Programmazione in RTAI: 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

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

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

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à’

Programmazione in RTAI Problema della ‘Inversione della priorità’

#include <linux/kernel. h> /* decls needed for kernel modules */ #include <linux/module. h> /*

#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 t 1, t 2, t 3; void prio. High(long arg); void prio. Medium(long arg); void prio. Low(long arg); static SEM sync, SEM sem. Binary; int global = 0; void binary(void) { int retval; rt_sem_init(&sync, 0); rt_typed_sem_init(&sem. Binary, 1, BIN_SEM | FIFO_Q ); retval = rt_task_init(&t 1, prio. High , 1, 1024, HIGH , 0, 0); retval = rt_task_init(&t 2, prio. Medium, 2, 1024, MEDIUM, 0, 0); retval = rt_task_init(&t 3, prio. Low , 3, 1024, LOW , 0, 0); retval = rt_task_resume(&t 1); retval = rt_task_resume(&t 2); retval = rt_task_resume(&t 3); while(!(rt_get_task_state(&t 1) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t 2) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t 3) & RT_SCHED_SEMAPHORE)); rt_sem_broadcast(&sync); }

int init_module(void) { printk("start of init_modulen"); rt_set_oneshot_mode(); start_rt_timer(1); binary(); printk("end of init_modulen"); return 0;

int init_module(void) { printk("start of init_modulen"); rt_set_oneshot_mode(); start_rt_timer(1); binary(); printk("end of init_modulen"); return 0; } void cleanup_module(void) { return; } void prio. Low(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON CPU %d. n", arg, &t 3, hard_cpu_id()); rt_sem_wait(&sync); for (i=0; i < ITER; i++) { rt_sem_wait(&sem. Binary); /* wait indefinitely for semaphore */ rt_printk("Low priority task locks semaphoren"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_printk("Low priority task starts unlock semaphoren"); rt_sem_signal(&sem. Binary); /* give up semaphore */ rt_printk("Low priority task has unlocked semaphoren"); } rt_printk(". . . . . Low priority task exitedn"); }

void prio. Medium(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON

void prio. Medium(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON CPU %d. n", arg, &t 2, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano 2 count(10000000)); /* lascia tempo per i thread a bassa priorità */ for (i=0; i < ITER; i++) { rt_printk("Medium task runningn"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + LONG_TIME)); } rt_printk("---------------Medium priority task exitedn"); } void prio. High(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON CPU %d. n", arg, &t 1, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano 2 count(30000000)); /* lascia tempo */ for (i=0; i < ITER; i++) { rt_printk("High priority task trys to lock semaphoren"); rt_sem_wait(&sem. Binary); /* wait indefinitely for semaphore */ rt_printk("High priority task locks semaphoren"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_sem_signal(&sem. Binary); /* give up semaphore */ rt_printk("High priority task unlocks semaphoren"); } rt_printk(". . . . High priority task exitedn"); }

Programmazione in RTAI Algoritmo priority inversion – implementazione in RTAI – Si risolve con

Programmazione in RTAI Algoritmo priority inversion – implementazione in RTAI – Si risolve con semafori di tipo resource: rt_typed_sem_init(&sem. Binary, 1, BIN_SEM | FIFO_Q );

#include <linux/kernel. h> /* decls needed for kernel modules */ #include <linux/module. h> /*

#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 t 1, t 2, t 3; void prio. High(long arg); void prio. Medium(long arg); void prio. Low(long arg); static SEM sync, SEM sem. Binary; ; // semafori int global = 0; void binary(void) { int retval; rt_sem_init(&sync, 0); rt_typed_sem_init(&sem. Binary, 1, RES_SEM | FIFO_Q ); retval = rt_task_init(&t 1, prio. High , 1, 1024, HIGH , 0, 0); retval = rt_task_init(&t 2, prio. Medium, 2, 1024, MEDIUM, 0, 0); retval = rt_task_init(&t 3, prio. Low , 3, 1024, LOW , 0, 0); retval = rt_task_resume(&t 1); retval = rt_task_resume(&t 2); retval = rt_task_resume(&t 3); while(!(rt_get_task_state(&t 1) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t 2) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t 3) & RT_SCHED_SEMAPHORE)); rt_sem_broadcast(&sync); }

void prio. Low(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON

void prio. Low(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON CPU %d. n", arg, &t 3, hard_cpu_id()); rt_sem_wait(&sync); for (i=0; i < ITER; i++) { rt_sem_wait(&sem. Binary); /* wait indefinitely for semaphore */ rt_printk("Low priority task locks semaphoren"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_printk("Low priority task unlocks semaphoren"); rt_sem_signal(&sem. Binary); /* give up semaphore */ } rt_printk(". . . . . Low priority task exitedn"); } void prio. Medium(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON CPU %d. n", arg, &t 2, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano 2 count(20000000)); /* allow time for task with the lowest priority to seize semaphore */ for (i=0; i < ITER; i++) { rt_printk("Medium task runningn"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + LONG_TIME)); } rt_printk("---------------------Medium priority task exitedn"); }

void prio. High(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON

void prio. High(long arg) { RTIME startime; int i; rt_printk("RESUMED TASK #%d (%p) ON CPU %d. n", arg, &t 1, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano 2 count(30000000)); /* lascia tempo ai task di piu’ bassa priorità */ for (i=0; i < ITER; i++) { rt_printk("High priority task trys to lock semaphoren"); rt_sem_wait(&sem. Binary); /* wait indefinitely for semaphore */ rt_printk("High priority task locks semaphoren"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_printk("High priority task unlocks semaphoren"); rt_sem_signal(&sem. Binary); /* give up semaphore */ } rt_printk(". . . . . High priority task exitedn"); } int init_module(void) { printk(“inizia init_modulen"); rt_set_oneshot_mode(); start_rt_timer(1); binary(); printk("end of init_modulen"); return 0; } void cleanup_module(void) { return; }