Esempi di Programmazione RTAI



Documenti analoghi
RTAI e scheduling. Andrea Sambi

Schedulazione in RTAI

Estensioni Linux per il Real-Time

Introduzione ai Moduli del Kernel di Linux. E.Mumolo, DEEI

Pronto Esecuzione Attesa Terminazione

Monitor. Introduzione. Struttura di un TDA Monitor

Con il termine Sistema operativo si fa riferimento all insieme dei moduli software di un sistema di elaborazione dati dedicati alla sua gestione.

Tesina per l esame di Sistemi Operativi a cura di Giuseppe Montano. Prof. Aldo Franco Dragoni

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

I/O su Socket TCP: read()

STRUTTURE DEI SISTEMI DI CALCOLO

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Inter Process Communication. Laboratorio Software C. Brandolese

Comunicazione. La comunicazione point to point e' la funzionalita' di comunicazione fondamentale disponibile in MPI

Scheduling. Sistemi Operativi e Distribuiti A.A Bellettini - Maggiorini. Concetti di base

1. Che cos è la multiprogrammazione? Si può realizzare su un sistema monoprocessore? 2. Quali sono i servizi offerti dai sistemi operativi?

Computazione multi-processo. Condivisione, Comunicazione e Sincronizzazione dei Processi. Segnali. Processi e Threads Pt. 2

Sistemi Operativi. Lez. 13: primitive per la concorrenza monitor e messaggi

Sincronizzazione e comunicazione tra processi in Unix. usati per trasferire ad un processo l indicazione che un determinato evento si è verificato.

Modello dei processi. Riedizione delle slide della Prof. Di Stefano

Sistemi Operativi. Interfaccia del File System FILE SYSTEM : INTERFACCIA. Concetto di File. Metodi di Accesso. Struttura delle Directory

Sistemi Operativi (modulo di Informatica II) I processi

Introduzione alla programmazione in C

Il sistema di I/O. Hardware di I/O Interfacce di I/O Software di I/O. Introduzione

Architettura di un sistema di calcolo

Esercitazione [5] Input/Output su Socket

Il Sistema Operativo

RTAI IPC. Andrea Sambi

Thread: sincronizzazione Esercitazioni del 09 Ottobre 2009

Scheduling della CPU Simulazione in linguaggio Java

Algoritmi di scheduling

Lo scheduler di UNIX (1)

Java Virtual Machine

Organizzazione Monolitica

Laureando: Damiano Vittor. Relatore: Dott. Ing. Massimiliano Nolich

Scheduling della CPU:

Corso di Sistemi Operativi Ingegneria Elettronica e Informatica prof. Rocco Aversa. Raccolta prove scritte. Prova scritta

IL SISTEMA OPERATIVO

Arduino: Programmazione

Sistemi Operativi. Scheduling della CPU SCHEDULING DELLA CPU. Concetti di Base Criteri di Scheduling Algoritmi di Scheduling

Sistemi Operativi SCHEDULING DELLA CPU. Sistemi Operativi. D. Talia - UNICAL 5.1

Corso di Linguaggi di Programmazione

Sistemi Operativi mod. B. Sistemi Operativi mod. B A B C A B C P P P P P P < P 1, >

ASPETTI GENERALI DI LINUX. Parte 2 Struttura interna del sistema LINUX

dall argomento argomento della malloc()

Il memory manager. Gestione della memoria centrale

Scheduling della CPU

Capitolo 3 -- Silberschatz

Corso di Sistemi di Elaborazione delle informazioni

Programmazione I - Laboratorio

Sistemi Operativi SCHEDULING DELLA CPU

Sistema Operativo. Fondamenti di Informatica 1. Il Sistema Operativo

Allocazione dinamica della memoria - riepilogo

Sistemi Operativi Esercizi Sincronizzazione

CAPITOLO 7 - SCAMBIO DI MESSAGGI

Sistemi Operativi MECCANISMI E POLITICHE DI PROTEZIONE. D. Talia - UNICAL. Sistemi Operativi 13.1

MECCANISMI E POLITICHE DI PROTEZIONE 13.1

Sistemi Operativi (modulo di Informatica II)

Capitolo 7: Sincronizzazione

Scheduling della CPU. Sistemi multiprocessori e real time Metodi di valutazione Esempi: Solaris 2 Windows 2000 Linux

Approccio stratificato

DMA Accesso Diretto alla Memoria

Sistemi Operativi. Lezione 7 Comunicazione tra processi

SISTEMI OPERATIVI. Sincronizzazione dei processi. Domande di verifica. Luca Orrù Centro Multimediale Montiferru 30/05/2007

Il descrittore di processo (PCB)

I Thread. I Thread. I due processi dovrebbero lavorare sullo stesso testo

GESTIONE INFORMATICA DEI DATI AZIENDALI

Processi. Laboratorio Software C. Brandolese

GESTIONE DEI PROCESSI

I thread nel sistema operativo LINUX: Linuxthreads

Gestione dei processi. Marco Cesati. Schema della lezione. Blocco di controllo 2. Sezioni e segmenti. Gestione dei processi. Job.

Valutazione delle Prestazioni. Valutazione delle Prestazioni. Architetture dei Calcolatori (Lettere. Tempo di risposta e throughput

Le funzioni in C. I programmi C sono costituiti da definizioni di variabili e funzioni.

La memoria centrale (RAM)

Funzioni. Il modello console. Interfaccia in modalità console

Input/Output. Moduli di Input/ Output. gestiscono quantità di dati differenti a velocità diverse in formati diversi. n Grande varietà di periferiche

Il software di base comprende l insieme dei programmi predisposti per un uso efficace ed efficiente del computer.

Nascita di Java. Che cos e Java? Caratteristiche di Java. Java: linguaggio a oggetti

La prima applicazione Java. Creazione di oggetti - 1. La prima applicazione Java: schema di esecuzione. Gianpaolo Cugola - Sistemi Informativi in Rete

Laboratorio di Ingegneria del software Sistema di controllo di un ascensore Requisisti preliminari

Architettura hardware

Lezione E12. Sistemi operativi open-source, embedded e real-time

Processi e thread. Dipartimento di Informatica Università di Verona, Italy. Sommario

Sistemi Operativi. Scheduling dei processi

FONDAMENTI di INFORMATICA L. Mezzalira

Sistemi Operativi Kernel

Lo schedulatore del kernel

Il Sistema Operativo. C. Marrocco. Università degli Studi di Cassino

Transcript:

Esempi di 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

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

Programmazione in RTAI Primo esempio: #include <linux/kernel.h> #include <linux/module.h> MODULE_LICENSE("GPL"); int init_module(void) //entry point printk("hello world!\n"); // printk = scrive in /var/log/messages return 0; void cleanup_module(void)//exit point printk("goodbye world!\n"); return;

Programmazione in RTAI Compilazione sorgenti: usare il Makefile del kernel make f Makefile C <kernel path> M=$PWD Genera il file <modulo.ko> Nel nostro caso: EXTRA_CFLAGS += -I/usr/realtime/include -D_IN_RTAI_ obj-m += prog1.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean Per eseguire il modulo: insmod <modulo.ko> Per terminare : rmmod <modulo.ko>

Programmazione in RTAI Attenzione (1): printk scrive nel kernel ring buffer Il buffer viene scritto periodicamente sul file di log /var/log/messages Attenzione (2): printk può non essere predicibile: rt_printk versione RT Scrive sul kernel Ring buffer. Per leggere/cancellare il buffer: chiamate di sistema: syslog, klogctl - read 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 dmesg Oppure: tail -f /var/log/messages

Programmazione in RTAI Definizione di un task (thread in tempo reale): int rt_task_init(rt_task *task, void(*rt_thread)(int), int data, int stack_size, int priority, int uso_fpu, void(*signal)(void)); Attenzione: definisce il task, non l esegue! Il task si trova nello stato SUSPENDED Argomenti della funzione: Primo argomento: descrittore del task Secondo argomento: entry point della funzione Terzo argomento: un intero passato dal genitore al thread Quarto argomento: dimensione dello stack Quinto argomento: priorità. Da rtai_sched.h: #define RT_SCHED_HIGHEST_PRIORITY 0 #define RT_SCHED_LOWEST_PRIORITY 0x3fffFfff #define RT_SCHED_LINUX_PRIORITY 0x7fffFfff Sesto argomento: flag per l uso della fpu Settimo argomento: funzione per gestire il segnale inviato ogni volta che il thread diventa running

Programmazione in RTAI Schedulazione in RTAI: periodica aperiodica (one-shot) Modalità di funzionamento: void rt_set_oneshot_mode(void);//imposta lo schedulatore I task possono essere eseguiti in istanti qualsiasi void rt_set_periodic_mode(void); );//imposta lo schedulatore Ogni richiesta non multiplo del periodo viene soddisfatta nel periodo di base del timer più vicino. È il default. La schedulazione è associata al timer: RTIME start_rt_timer(int period);//se aperiodic il periodo è ignorato RTIME rt_get_time();//ticks se periodico, TSC se aperiodico void stop_rt_timer(void); Esempio: rt_set_oneshot_mode(); start_rt_timer(1); RTIME Internal count units; // misura il tempo trascorso in ticks Tempi: 1 tick=838 ns (timer del PC) Inoltre: Time Stamp Clock (TSC): clock del PC

Programmazione in RTAI Attivazione timer: periodico void rt_set_periodic_mode(void); RTIME start_rt_timer(rtime period); one-shot void rt_set_oneshot_mode(void); RTIME start_rt_timer(rtime period); La funzione RTIME nano2counts(int nanoseconds); converte da ns a ticks

Programmazione in RTAI Esecuzione di un task in tempo reale: due modalità Rende un processo RTAI periodico ed avvia la prima esecuzione all istante <start_time>: int rt_task_make_periodic(rt_task *task, RTIME start_time, RTIME period); Task aperiodico (one shot): esecuzione immediata int rt_task_resume(rt_task *task); esecuzione ad un istante assoluto start_time int rt_task_make_periodic(rt_task *task, RTIME start_time, RTIME period); //period non usato esecuzione ad un istante relativo start_delay int rt_task_make_periodic_relative_ns (RT_TASK *task, RTIME start_delay, RTIME period);

Programmazione in RTAI In definitiva per creare un task aperiodico: rt_set_oneshot_mode(); start_rt_timer(1); retval =rt_task_init(&task, function, 0, 1024, RT_SCHED_LOWEST_PRIORITY, 0, 0); retval = rt_task_resume(&task); Gestione della schedulazione: Nel caso di task periodico int rt_task_wait_period(void); sospende l esecuzione del thread corrente fino al prossimo periodo Nel caso di task aperiodico int rt_task_yield(void); int rt_task_suspend(rt_task *task); task_yield Fa assumere al processo chiamante lo stato READY task_suspend sospende l esecuzione, che verrà ripresa con resume o con make_periodic Programma d esempio: crea un task aperiodico

#include <linux/kernel.h> /* dichiarazioni richieste dai moduli del kernel */ #include <linux/module.h> /* dichiarazioni richieste dai moduli del kernel */ #include <linux/version.h> #include <linux/errno.h> /* EINVAL, ENOMEM */ #include "rtai.h" #include "rtai_sched.h" #include <rtai_sem.h> MODULE_LICENSE("GPL"); static RT_TASK print_task; void print_function(long arg) rt_printk("hello world!\n"); return; int init_module(void) int retval; rt_set_oneshot_mode(); start_rt_timer(1); //parte l esecuzione retval = /* crea il tread real time */ rt_task_init(&print_task, print_function, 0, 1024, RT_SCHED_LOWEST_PRIORITY, 0, 0); if ( retval!= 0) if (-EINVAL == retval) printk("task: task structure is invalid\n"); else printk("task: error starting task\n"); return retval; retval = rt_task_resume(&print_task); /* punta alla nostra struttura */ if (0!= retval) if (-EINVAL == retval) printk("struttura task invalida\n"); else printk("task: error starting task\n"); return retval; return 0; void cleanup_module(void) return;

Programmazione in RTAI Funzioni di utilità per la schedulazione: void rt_sleep(rtime delay); void rt_sleep_until(rtime time); sospendono il thread in esecuzione e lo mettono in stato DELAYED void rt_busy_sleep(int nanosecs); addormenta in thread mandando in loop la CPU per il tempo indicato void rt_sched_lock(void); void rt_sched_unlock(void); blocca/sblocca lo schedulatore pe evitare corse critiche int rt_get_prio(rt_task *task); int rt_change_prio(rt_task *task, int priority; determina/setta la priorità di base int rt_get_inher_prio(rt_task *task); Determina la priorità ereditata a causa dell accesso a risorse condivise (protocolli priority inheritance)

Programmazione in RTAI Altre funzioni di utilità per la schedulazione: int rt_get_task_state(rt_task *task); RT_TASK *rt_whoami(void); int rt_task_use_fpu(rt_task *task, int use_fpu_flag); int rt_task_delete(rt_task *task); rimuove is task dal sistema

Programmazione in RTAI: Schedulazione periodica Non c è particolare limite al numero di task I task sono thread: condividono lo spazio di indirizzamento!! Attenzione alla mutua esclusione Dobbiamo determinare il periodo di base. Il periodo dei thread è un multiplo del periodo di base Programma d esempio: setto il timer a 1 ms definisco la funzione schedulazione

#include <linux/kernel.h> #include <linux/module.h> #include <linux/version.h> #include <linux/sched.h> #include <linux/errno.h> #include <asm/io.h> #include "rtai.h" #include "rtai_sched.h" MODULE_LICENSE("GPL"); static RT_TASK sound_task; static RT_TASK delay_task; static RTIME sound_period_ns = 1e5; /* in nanoseconds, -> 10 khz */ static RTIME delay_period_ns = 1e9; /* in nanoseconds, -> 1 Hz */ #define SOUND_PORT 0x61 /* indrizzo altoparlante */ #define SOUND_MASK 0x02 /* bit da cambiare */ static int delay_count = 2; // condivisa tra i due threa: onda quadra per altoparlante int init_module(void) RTIME sound_period_count, delay_period_count, timer_period_count; int retval; rt_set_periodic_mode(); sound_period_count = nano2count(sound_period_ns); delay_period_count = nano2count(delay_period_ns); timer_period_count = start_rt_timer(sound_period_count); printk("sound task: requested %d counts, got %d counts\n",(int) sound_period_count, (int) timer_period_count); retval = //struttura del thread sound rt_task_init(&sound_task, sound_function, 0, 1024, RT_LOWEST_PRIORITY - 1, 0, 0); if (0!= retval) if (-EINVAL == retval) printk("sound task: task structure already in use\n"); else if (-ENOMEM == retval) printk("sound task: can't allocate stack\n"); else printk("sound task: error initializing task structure\n"); return retval;

retval = //struttura del thread delay rt_task_init(&delay_task, delay_function, 0, 1024, RT_LOWEST_PRIORITY, 0, 0); if (0!= retval) if (-EINVAL == retval) printk( errore: gia in uso\n"); else if (-ENOMEM == retval) printk( errore di stack\n"); else printk( error di inizializzazione\n"); return retval; retval = //esegue il thread sund rt_task_make_periodic(&sound_task, rt_get_time() + sound_period_count, sound_period_count); if (0!= retval) if (-EINVAL == retval) printk("sound errore\n"); else printk("sound errore task\n"); return retval; retval = //esegue il thread delay rt_task_make_periodic(&delay_task, rt_get_time() + delay_period_count, delay_period_count); if (0!= retval) if (-EINVAL == retval) printk( errore delay \n"); else printk("delay task: error starting task\n"); return retval; return 0; /* success! */

void sound_function(int arg) int delay_left = delay_count; /* decrementato ad ogni ciclo */ unsigned char sound_byte, toggle = 0; while (1) if (delay_left > 0) //ritardo restante? delay_left--; else sound_byte = inb(sound_port); if (toggle) sound_byte = sound_byte SOUND_MASK; else sound_byte = sound_byte & ~SOUND_MASK; outb(sound_byte, SOUND_PORT); toggle =! toggle; delay_left = delay_count; rt_task_wait_period(); /* ricarico il ritardo*/ /* non arriviamo mai qui */ return; void delay_function(int arg) while (1) delay_count++; rt_task_wait_period(); /* non arriviamo mai qui */ return;

void cleanup_module(void) int retval; retval = rt_task_delete(&sound_task); if (0!= retval) if (-EINVAL == retval) /* invalid task structure */ printk("sound task: task structure is invalid\n"); else printk("sound task: error stopping task\n"); retval = rt_task_delete(&delay_task); if (0!= retval) if (-EINVAL == retval) /* invalid task structure */ printk("delay task: task structure is invalid\n"); else printk("delay task: error stopping task\n"); outb(inb(sound_port) & ~SOUND_MASK, SOUND_PORT); //toggle il bit return;

Programmazione in RTAI Politiche di schedulazione RTAI offre la possibilità di usare le seguenti politiche: FIFO (default), Round Robin. Abilitazione delle politiche: void rt_set_sched_policy(struct rt_task_struct *task, int policy, int rr_quantum_ns); Politiche: RT_SCHED_RR - RT_SCHED_FIFO Esempio: 3 task: appena creati sono bloccati da un semaforo che viene aperto appena possono continuare. Ogni task esegue per EXECTIME unità temporali, realizzato come segue: starttime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (starttime + EXECTIME)); Vene contato il numero di context switch mediante un semaforo

Programmazione in RTAI In definitiva, la sched. FIFO si realizza con queste istruzioni: void func1(); void func2(); int init_module() rt_set_periodic_mode(); rt_task_init(&t1,func1, ); rt_task_init(&t2,func2, ); rt_task_make_periodic(&t1,start1,periodo1); rt_task_make_periodic(&t2,start1,periodo2); NB: FIFO può essere facilmente anche RM

#include <linux/kernel.h> #include <linux/kernel.h> #include <linux/module.h> #include <rtai.h> #include <rtai_sched.h> #include <rtai_sem.h> MODULE_LICENSE("GPL"); #define STACK_SIZE 2000 #define EXECTIME 400000000 #define RR_QUANTUM 10000000 #define NTASKS 3 #define PRIORITY 100 static SEM sync, RT_TASK tasks[ntasks], int switchescount[ntasks]; static void fun(long indx) //funzione eseguita dai task RTIME starttime, endtime;; rt_printk("resume task #%d (%p) on CPU %d.\n", indx, &tasks[indx], hard_cpu_id()); rt_sem_wait(&sync); rt_printk("task #%d (%p) inizia on CPU %d.\n", indx, &tasks[indx], hard_cpu_id()); starttime = rt_get_cpu_time_ns(); //esegue per EXECTIME while(rt_get_cpu_time_ns() < (starttime + EXECTIME)); endtime = rt_get_cpu_time_ns()-starttime; //segnala il nr di context switch tasks[indx].signal = 0; rt_printk("task #%d (%p) terminates after %d.\n", indx, &tasks[indx],endtime); static void signal(void) //esegue quando c e un context switch RT_TASK *task; int i; for (i = 0; i < NTASKS; i++) if ((task = rt_whoami()) == &tasks[i]) switchescount[i]++; rt_printk("switch al task #%d (%p) on CPU %d.\n", i, task, hard_cpu_id()); break;

int init_module(void) int i; printk("insmod on CPU %d.\n", hard_cpu_id()); rt_sem_init(&sync, 0); rt_set_oneshot_mode(); start_rt_timer(1); for (i = 0; i < NTASKS; i++) rt_task_init(&tasks[i], fun, i, STACK_SIZE, PRIORITY, 0, signal); for (i = 0; i < NTASKS; i++) rt_task_resume(&tasks[i]); rt_sem_broadcast(&sync); return 0; void cleanup_module(void) int i; stop_rt_timer(); rt_sem_delete(&sync); for (i = 0; i < NTASKS; i++) printk("nr di context switches task # %d -> %d\n", i, switchescount[i]); rt_task_delete(&tasks[i]);

Programmazione in RTAI Schedulazione prioritaria: I thread hanno una priorità tra 0 (RT_SCHED_HIGHEST_PRIORITY) e 1,073,741,823 (RT_SCHED_LOWEST_PRIORITY ) Quando si crea un task con rt_task_init(..) uno degli argomenti è la priorità Dopo che viene eseguito un task può variare priorità con int rt_change_prio( RT_TASK *task, intpriority) ; La politica prioritaria è RT_SCHED_FIFO Esempio: creazione di 3 task a diverse priorità. Provae a cambiare le priorità

#include <linux/kernel.h> #include <linux/module.h> #include <rtai.h> #include <rtai_sched.h> #include <rtai_sem.h> MODULE_LICENSE("GPL"); #define STACK_SIZE 2000 #define EXECTIME 400000000 #define RR_QUANTUM 10000000 #define NTASKS 3 #define HIGH 100 #define MID 101 #define LOW 102 static SEM sync, RT_TASK tasks[ntasks], int switchescount[ntasks]; static void fun(long indx) RTIME starttime, endtime; rt_printk("resume task #%d (%p) on CPU %d.\n", indx, &tasks[indx], hard_cpu_id()); rt_sem_wait(&sync); rt_printk("task #%d (%p) inizia su CPU %d.\n", indx, &tasks[indx], hard_cpu_id()); starttime = rt_get_cpu_time_ns(); //esegue per EXECTIME while(rt_get_cpu_time_ns() < (starttime + EXECTIME)); endtime = rt_get_cpu_time_ns()-starttime; tasks[indx].signal = 0; rt_printk("task #%d (%p) terminates after %d.\n", indx, &tasks[indx],endtime);

static void signal(void) //per segnalare il nr di context switches RT_TASK *task; int i; for (i = 0; i < NTASKS; i++) if ((task = rt_whoami()) == &tasks[i]) switchescount[i]++; rt_printk( passa a #%d (%p) su %d.\n", i, task, hard_cpu_id()); break; int init_module(void) int i; printk("insmod on CPU %d.\n", hard_cpu_id()); rt_sem_init(&sync, 0); rt_set_oneshot_mode(); start_rt_timer(1); rt_task_init(&tasks[0], fun, 0, STACK_SIZE, LOW, 0, signal); rt_task_init(&tasks[1], fun, 1, STACK_SIZE, MID, 0, signal); rt_task_init(&tasks[2], fun, 2, STACK_SIZE, HIGH, 0, signal); for (i = 0; i < NTASKS; i++) rt_task_resume(&tasks[i]); while(!(rt_get_task_state(&tasks[i]) & RT_SCHED_SEMAPHORE)); rt_sem_broadcast(&sync); return 0; void cleanup_module(void) int i; stop_rt_timer(); rt_sem_delete(&sync); for (i = 0; i < NTASKS; i++) printk("number of context switches task # %d -> %d\n", i, switchescount[i]); rt_task_delete(&tasks[i]);

Programmazione in RTAI Schedulazione RateMonotonic (RM)

#include <linux/kernel.h> /* decls needed for kernel modules */ #include <linux/module.h> /* decls needed for kernel modules */ #include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION() */ #include <linux/errno.h> /* EINVAL, ENOMEM */ #include "rtai.h" #include "rtai_sched.h" #include <rtai_sem.h> MODULE_LICENSE("GPL"); #define NTASKS 3 #define STACK_SIZE 10000 static RT_TASK tasks[ntasks]; static int task_arg[ntasks]; #define BASE_PERIOD_NS 1000000 static RTIME base_period; // in internal units static RTIME base_period_us; // in microseconds static RTIME base_period_ns; // in nanoseconds static int task_computation_time[ntasks] = 30, 20, 20 ; //timer periodici static int task_period[ntasks] = 60, 90, 110 ; static int task_priority[ntasks] = 10, 20, 30 ; static int ggd=1980; // 6*9*11/3 RTIME resumetime[ntasks], deadlinetime[ntasks]; int nodeadlinemiss=1; static SEM sync; static RTIME tasks_starttime=0; static int switchescount[ntasks]; #define CALIBRATION_PERCENTAGE 100 //parametro per l attesa attiva #define CALIBRATION_LOOP_SIZE 1e7 //più alto (non troppo) più accurato static RT_TASK init_task_str; static RTIME count_need_for_one_ms_busysleep; static int task_period_counter[ntasks] = 0, 0, 0 ; inline RTIME loop(rtime count) //esegue un loop da 0 a count unsigned long int i; // ritorna il tempo in ns per eseguire un loop RTIME starttime, sleeptime_ns; starttime = rt_get_time_ns(); for (i = 0; i < count ; i++) sleeptime_ns=rt_get_time_ns()-starttime; return sleeptime_ns;

/* function to callibrate busysleep function */ void calibrate_busysleep(void) RTIME sleeptime_ns; RTIME x; volatile RTIME loop_size=calibration_loop_size; // loop with global CALIBRATION_LOOP_SIZE sleeptime_ns=loop(loop_size); rt_printk("sleeptime_ns=%lld\n",sleeptime_ns); // // sleeptime_in_us = sleeptime_ns/1000 // count_need_for_one_us_busysleep=calibration_loop_size/sleeptime_in_us; // -> somma fattore di calibrazione : // sleeptime_in_us -> sleeptime_in_us * calibrationpercentage/100 // -> in definitiva // counterbusysleepns= calibration_loop_size*10*calibrationpercentage/sleeptime_ns x=calibration_loop_size*10*calibration_percentage*1000; do_div(x,sleeptime_ns); // fattore di calibrazione ttale count_need_for_one_ms_busysleep=x;

//tiene il processore occuato per sleeptime_us, ritorna il tempo passato RTIME busysleep(rtime sleeptime_us ) RTIME temp; RTIME sleeptime_ns; RTIME sleep_count; sleep_count= count_need_for_one_ms_busysleep*sleeptime_us; do_div(sleep_count,1000); sleeptime_ns=loop(sleep_count); return sleeptime_ns; // calibrazione della attesa attiva rt_printk("------------------------------------------ init task started\n",arg); calibrate_busysleep(); rt_printk("count_need_for_one_ms_busysleep=%lld\n", count_need_for_one_ms_busysleep); rt_printk("------------------------------------------ init task ended\n",arg); return; // time_in_base_periods=(rt_get_time()-starttime )/base_period // -> integer part : RTIME time_int(rtime temp) do_div(temp,base_period); return temp; // -> first two digits : RTIME time_digits(rtime temp) RTIME rest; rest=do_div(temp,base_period); temp=rest*100; do_div(temp,base_period); return temp;

RTIME get_time() //calcola il tempo di esecuzione RTIME temp; temp=rt_get_time()-tasks_starttime; return temp; void print_info(int currenttask,char *msg) RTIME now=get_time(); rt_printk("t%d %s - time %3lld.%02lld - computation %3d - period %3d - interval %d-%d \n",currenttask, msg, time_int(now),time_digits(now), task_computation_time[currenttask], task_period[currenttask], task_period_counter[currenttask]*task_period[currenttask], (task_period_counter[currenttask]+1)*task_period[currenttask]); void dummy_task(long t) /calibrazione RTIME cur_task_sleeptime_ns, cur_task_sleeptime_us, base_periods_passed, cur_task_period; cur_task_period=task_period[t]*base_period; cur_task_sleeptime_us=base_period_us*task_computation_time[t]; task_period_counter[t]=0; base_periods_passed=0; if (!tasks_starttime) tasks_starttime=rt_get_time(); while( time_int(get_time()) < ggd && nodeadlinemiss ) resumetime[t]=tasks_starttime + (task_period_counter[t]*cur_task_period); deadlinetime[t]=resumetime[t]+cur_task_period; print_info(t,"start "); cur_task_sleeptime_ns=busysleep(cur_task_sleeptime_us); if ( rt_get_time() >= deadlinetime[t] + base_period ) rt_printk("\n\n\n"); rt_printk(" TASK %d missed deadline %d", t, (task_period_counter[t]+1)*task_period[t] ); rt_printk("\n\n\n"); nodeadlinemiss=0; print_info(t,"stop "); rt_task_wait_period(); task_period_counter[t]++; print_info(t,"ended ");if (nodeadlinemiss) rt_printk("\n\n SCHEDULABILE\n\n ", t); return;

int init_module(void) //parte il task con chedulaione specifica int i; RTIME temp,starttime; printk( inizia init_module\n"); printk("insmod on CPU %d.\n", hard_cpu_id()); rt_sem_init(&sync, 0); rt_set_periodic_mode(); //configura il modo base_period = start_rt_timer(nano2count(base_period_ns)); rt_printk("base_period : %lld.\n\n",base_period); base_period_ns=count2nano(base_period); rt_printk("base_period_ns : %lld.\n\n",base_period_ns); temp=base_period_ns; do_div(temp,1000); base_period_us=temp; // base_period_us=count2nano(base_period)/1000; rt_printk("base_period_us : %lld.\n\n",base_period_us); rt_task_init(&init_task_str, init, 0, STACK_SIZE, 100, 0, 0); rt_task_resume(&init_task_str); for (i = 0; i < NTASKS; i++) task_arg[i]=i; // il task fittizio parte subito rt_task_init(&tasks[i], dummy_task, task_arg[i], STACK_SIZE, task_priority[i], 1, 0); starttime=rt_get_time()+1000000; for (i = 0; i < NTASKS; i++) rt_task_make_periodic(&tasks[i], starttime,task_period[i]*base_period); printk("end of init_module\n"); return 0;

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

Schedulazione EarliestDeadlineFirst (EDF) #include <linux/module.h> #include <asm/io.h> #include <asm/rtai.h> #include <rtai_sched.h> #define ONE_SHOT #define TICK_PERIOD 10000000 #define STACK_SIZE 2000 #define LOOPS 3 #define NTASKS 8 static RT_TASK thread[ntasks]; static RTIME tick_period; static int cpu_used[nr_rt_cpus]; static void fun(long t) unsigned int loops = LOOPS; while(loops--) cpu_used[hard_cpu_id()]++; rt_printk("task %d with priority %d in loop %d \n", t, thread[t].priority,loops); rt_task_set_resume_end_times(-ntasks*tick_period, -(t + 1)*tick_period); rt_printk("task %d with priority %d ENDS\n", t, thread[t].priority);

EDF (cont.) int init_module(void) RTIME now; int i; #ifdef ONE_SHOT rt_set_oneshot_mode(); #endif for (i=0;i<ntasks;i++) rt_task_init(&thread[i],fun,i,stack_size,ntasks-i-1,0,0); tick_period = start_rt_timer(nano2count(tick_period)); now = rt_get_time() + NTASKS*tick_period; for (i = 0; i < NTASKS; i++) rt_task_make_periodic(&thread[ntasks - i - 1], now, NTASKS*tick_period); return 0; void cleanup_module(void) int i, cpuid; stop_rt_timer(); for (i = 0; i < NTASKS; i++) rt_task_delete(&thread[i]); printk("\n\ncpu USE SUMMARY\n"); for (cpuid = 0; cpuid < NR_RT_CPUS; cpuid++) printk("# %d -> %d\n", cpuid, cpu_used[cpuid]); printk("end OF CPU USE SUMMARY\n\n");

Programmazione in RTAI: IPC RTAI usa sistemi di IPC simili a Linux ma implementati separatamente: rt_fifo: scambio dati tra i thread in tempo reale, tra processi Linux, shared memory, tra thread in tempo reale e processi Linux mailbox semafori RPC

Programmazione in RTAI: IPC rt_fifo Per creare una rt_fifo: int rtf_create(unsigned int fifo, int size); Per dimensionare una rt_fifo: int rtf_resize(int fd, int size); Per creare/aprire una rt_fifo dallo spazio utente si usa file_descriptor = open("/dev/rtf0", O_RDONLY); Per creare/aprire una rt_fifo dallo spazio kernel si usa: int rtf_open_sized(const char *dev, int perm, int size); Le rt_fifo possono essere associate a dei command handler che vanno in esecuzione ogni volta che un processo nello spazio utente esegue una read() o una write() sulla fifo: int rtf_create_handler(unsigned int minor, int (*handler)(unsigned int fifo)););

Programmazione in RTAI: IPC rt_fifo: esempio d uso dei command handler int rtf_create_handler(fifo_numver, X_FIFO_HANDLER(x_handler); con, ad esempio, come x_handler: int x_handler(unsigned int fifo, int rw) if(rw== r ) //quello che bisogna fare in relazione ad una read else //quello che bisogna fare in relazione ad una write

Programmazione in RTAI: IPC rt_fifo: per evitare bloccaggi indeterminati int rtf_read_all_at_once(int fd, void *buf, int count); int rtf_read_timed(int fd, void *buf, int count, int ms_delay); int rtf_write_timed(int fd, void *buf, int count, int ms_delay); rt_fifo: uso dei semafori int rtf_sem_init(unsigned int fifo, int value); int rtf_sem_wait(unsigned int fifo); //solo dallo spazio utente int rtf_sem_trywait(unsigned int fifo); //solo dallo spazio utente...

Programmazione in RTAI: IPC Per accedere una rt_fifo Dal lato real time num_read = rtf_get(0, &buffer_in, sizeof(buffer_in)); num_written = rtf_put(1, &buffer_out, sizeof(buffer_out)); Dal lato Linux num_read = read(read_descriptor, &buffer_in, sizeof(buffer_in)); num_written = write(write_descriptor, &buffer_out,sizeof(buffer_out)); Letture bloccanti: Unix supporta sia lettura bloccanti che non In sistemi real time sono preferibili le letture non bloccanti: 'rtf_get()' ritorna immediatamente se non ci sono dati da leggere

//FIFO monodirezionali #include <linux/kernel.h> /* decls needed for kernel modules */ #include <linux/module.h> /* decls needed for kernel modules */ #include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION() */ #include <linux/errno.h> /* EINVAL, ENOMEM */ #include <rtai.h> #include <rtai_sched.h> #include <rtai_fifos.h> MODULE_LICENSE("GPL") ; static RT_TASK t1; static RT_TASK t2; void taskone(long arg); void tasktwo(long arg); #define MAX_MESSAGES 100 #define MAX_MESSAGE_LENGTH 50 void message(void) /* function to create the message queue and two tasks */ int retval; rtf_create (0,MAX_MESSAGES*MAX_MESSAGE_LENGTH); //crea una FIFO con numero 0 retval = rt_task_init(&t1,taskone, 0, 1024, 0, 0, 0); retval = rt_task_init(&t2,tasktwo, 0, 1024, 0, 0, 0); retval = rt_task_resume(&t1); //esegue i thread: attenzione all ordine retval = rt_task_resume(&t2);

void taskone(long arg) int retval; char message[] = "Received message from taskone"; rt_printk("taskone starts sending message\n"); retval = rtf_put(0, &message, sizeof(message)); //trasmette rt_printk("taskone continues after sending message\n"); void tasktwo(long arg) int retval; char msgbuf[max_message_length]; rt_printk("tasktwo ready to receive\n"); retval = rtf_get(0, &msgbuf, sizeof(msgbuf)); //riceve if (retval>0) rt_printk("tasktwo: %s\n", msgbuf); rt_printk(" lunghezza: %d\n", retval); else printk("fifo queue is empty\n"); int init_module(void) printk("start of init_module\n"); rt_set_oneshot_mode(); start_rt_timer(1); message(); printk("end of init_module\n"); return 0; void cleanup_module(void) stop_rt_timer(); rt_task_delete(&t1); rt_task_delete(&t2); return;

Altro esempio: FIFO bidirezionali #include <linux/kernel.h> #include <linux/module.h> #include <linux/version.h> #include <linux/errno.h> #include <rtai.h> #include <rtai_sched.h> #include <rtai_fifos.h> MODULE_LICENSE("GPL"); static RT_TASK t1; static RT_TASK t2; void taskone(long arg); void tasktwo(long arg); #define MAX_MESSAGES 100 #define MAX_MESSAGE_LENGTH 50 static RTIME delay_count, delay_ns = 1e6; /* in nanoseconds, -> 1 msec */ void message(void) /* function to create the message queue and two tasks */ int retval; rtf_create (1,MAX_MESSAGES*MAX_MESSAGE_LENGTH); //crea FIFO con id 0 rtf_create (2,MAX_MESSAGES*MAX_MESSAGE_LENGTH); rt_set_oneshot_mode(); start_rt_timer(1); delay_count = nano2count(delay_ns); //specifica il ritardo retval = rt_task_init(&t1,taskone, 0, 1024, 0, 0, 0); retval = rt_task_init(&t2,tasktwo, 0, 1024, 0, 0, 0); retval = rt_task_resume(&t1); retval = rt_task_resume(&t2); //esegue i thread

void taskone(long arg) int retval=0; char message[] = Messaggio dal taskone"; char msgbuf[max_message_length]; msgbuf[0]=0; rt_printk("taskone inizia a mandare un messaggio al tasktwo via FIFO\n"); retval = rtf_put(2, &message, sizeof(message)); //manda messaggio a tasktwo rt_printk("taskone continua\n"); t_sleep(delay_count); //aspetta per far partire tasktwo retval = rtf_get(1, &msgbuf, sizeof(msgbuf)); //riceve il messaggio if ( retval < 0 ) rt_printk("problem with fifo \n"); //test: cambia id in rtf_get else rt_printk("taskone riceve: %s con lunghezza: %d \n", msgbuf, retval); void tasktwo(long arg) int retval=0; char msgbuf[max_message_length]; char message[] = " Messaggio dal tasktwo "; msgbuf[0]=0; rt_printk(" tasktwo inizia a mandare un messaggio al taskone via FIFO\n "); retval = rtf_put(1, &message, sizeof(message)); //manda messaggio a taskone rt_printk("tasktwo continua\n"); rt_printk("tasktwo pronto per ricevere\n"); retval = rtf_get(2, &msgbuf, sizeof(msgbuf)); //riceve if ( retval < 0 ) rt_printk("problem with fifo \n"); else rt_printk("tasktwo receive: %s con lunghezza %d\n", msgbuf, retval);

int init_module(void) printk("start of init_module\n"); message(); printk("end of init_module\n"); return 0; void cleanup_module(void) stop_rt_timer(); rt_task_delete(&t1); rt_task_delete(&t2); return;

Programmazione in RTAI: IPC Mailbox: è un buffer gestito dal SO per scambio di messaggi tra processi e task 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 tipizzata int rt_typed_mbx_init(mbx *mbx, int size, int type)

Programmazione in RTAI: IPC Mailbox: per inviare/ricevere dati senza/con condizioni int rt_mbx_send(mbx *mbx, int size); int rt_mbx_receive(mbx *mbx, int size); int rt_mbx_send_wp(mbx *mbx, int size); int rt_mbx_receive_wp(mbx *mbx, int size); int rt_mbx_send_if(mbx *mbx, int size); int rt_mbx_receive_if(mbx *mbx, int size); Programma d esempio: taskone manda un messaggio via mailbox a tasktwo che lo scrive

#include <linux/kernel.h> /* 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 50 static 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

void taskone(long arg) /* task che scrive nella mailbox */ int retval; char message[] = ricvuto messaggio da TaskOne"; retval = rt_mbx_send(&mailboxid, message, sizeof(message)); //spedisce if (0!= retval) if (-EINVAL == retval) rt_printk("mailbox invalida\n"); else rt_printk( errore sconosciuto\n"); else rt_printk("taskone ha inviato messaggio\n"); void tasktwo(long arg) /* tasks che legge dalla mailbox */ int retval; char msgbuf[max_message_length]; retval = rt_mbx_receive_wp(&mailboxid, msgbuf, 50); if (-EINVAL == retval) rt_printk("mailbox invalida\n"); else rt_printk("tasktwo receive : %s con lunghezza %d\n",msgbuf, 50-retval); /* cancella la mailbox */ rt_mbx_delete(&mailboxid);

int init_module(void) printk( inizia init_module\n"); rt_set_oneshot_mode(); start_rt_timer(1); message(); printk( finisce init_module\n"); return 0; void cleanup_module(void) stop_rt_timer(); rt_task_delete(&t1); rt_task_delete(&t2); return;

Programmazione in RTAI: IPC IPC memoria condivisa (shared memory) Per trasferire dati tra processi e task Naturalmente sono molto veloci Svantaggi: non essendo serializzati necessitano di un protocollo di accesso il bloccaggio tra processi e task non è supportato bisogna gestire il trasferimento con un metodo non è garantita la mutua esclusione processi/task Non è possibile rilevare letture/scritture interrotte Tipi di shared memory: Mbuff: condivisione processi/thread (cioè spazio utente/spazio kernel) senza richiedere RTAI Shmem: condivisione processi/thread (cioè spazio utente/spaziokernel) che dipende profondamente da RTAI

Programmazione in RTAI: IPC mbuff: Implementata come device driver: device /dev/mbuff Per accedere alla memoria condivisa dallo spazio utente/kernel: void *mbuff_alloc(unsigned long name, unsigned int size); Per rilasciare la memoria: void mbuf_free(int name, void *mbuf);

IPC in RTAI: memoria condivisa shmem: Implementata come device driver: device /dev/rtai_shm Per accedere dallo spazio utente: void *rtai_malloc(unsigned long name, int size); Per rilasciarla: void rtai_free(int name, void *adr); Per accedere dallo spazio kernel: void *rtai_malloc(unsigned long name, int size); Per rilasciarla: void rtai_free(int name, void *adr);

IPC in RTAI: semafori Semafori: sono di tre tipi Counting: Usati per registrare eventi (CNT_SEM) Binary: Usati per gestire eventi binari (BIN_SEM) Resource: Usati per gestire l accesso a risorse mediante la priority inheritance (RES_SEM) Per inizializzare un semaforo: void rt_typed_sem_init(sem *sem, int value, int type); Per usare un semaforo: int rt_sem_wait(sem *sem); int rt_sem_signal(sem *sem); Per il test sulla condizione di blocco: int rt_sem_wait_if(sem *sem); Per il test sul tempo massimo di blocco: int rt_sem_wait_timed(sem *sem, RTIME delay);

Programmazione in RTAI Problema della Inversione della priorità

#include <linux/kernel.h> /* decls needed for kernel modules */ #include <linux/module.h> /* decls needed for kernel modules */ #include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION() */ #include <linux/errno.h> /* EINVAL, ENOMEM */ #include "rtai.h" /* RTAI configuration switches */ #include "rtai_sched.h #include <rtai_sem.h> MODULE_LICENSE("GPL"); #define ITER 10 #define HIGH 102 /* high priority */ #define MEDIUM 103 /* medium priority */ #define LOW 104 /* low priority */ #define NORMAL_TIME 20000000 /* nanoseconds */ #define LONG_TIME 50000000 /* nanoseconds */ static RT_TASK t1, t2, t3; void priohigh(long arg); void priomedium(long arg); void priolow(long arg); static SEM sync, SEM sembinary; int global = 0; void binary(void) int retval; rt_sem_init(&sync, 0); rt_typed_sem_init(&sembinary, 1, BIN_SEM FIFO_Q ); retval = rt_task_init(&t1,priohigh, 1, 1024, HIGH, 0, 0); retval = rt_task_init(&t2,priomedium, 2, 1024, MEDIUM, 0, 0); retval = rt_task_init(&t3,priolow, 3, 1024, LOW, 0, 0); retval = rt_task_resume(&t1); retval = rt_task_resume(&t2); retval = rt_task_resume(&t3); while(!(rt_get_task_state(&t1) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t2) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t3) & RT_SCHED_SEMAPHORE)); rt_sem_broadcast(&sync);

int init_module(void) printk("start of init_module\n"); rt_set_oneshot_mode(); start_rt_timer(1); binary(); printk("end of init_module\n"); return 0; void cleanup_module(void) return; void priolow(long arg) RTIME startime; int i; rt_printk("resumed TASK #%d (%p) ON CPU %d.\n", arg, &t3, hard_cpu_id()); rt_sem_wait(&sync); for (i=0; i < ITER; i++) rt_sem_wait(&sembinary);/* wait indefinitely for semaphore */ rt_printk("low priority task locks semaphore\n"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_printk("low priority task starts unlock semaphore\n"); rt_sem_signal(&sembinary); /* give up semaphore */ rt_printk("low priority task has unlocked semaphore\n"); rt_printk("...low priority task exited\n");

void priomedium(long arg) RTIME startime; int i; rt_printk("resumed TASK #%d (%p) ON CPU %d.\n", arg, &t2, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano2count(10000000));/* lascia tempo per i thread a bassa priorità */ for (i=0; i < ITER; i++) rt_printk("medium task running\n"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + LONG_TIME)); rt_printk("------------------------------medium priority task exited\n"); void priohigh(long arg) RTIME startime; int i; rt_printk("resumed TASK #%d (%p) ON CPU %d.\n", arg, &t1, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano2count(30000000));/* lascia tempo */ for (i=0; i < ITER; i++) rt_printk("high priority task trys to lock semaphore\n"); rt_sem_wait(&sembinary);/* wait indefinitely for semaphore */ rt_printk("high priority task locks semaphore\n"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_sem_signal(&sembinary); /* give up semaphore */ rt_printk("high priority task unlocks semaphore\n"); rt_printk("...high priority task exited\n");

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

#include <linux/kernel.h> /* decls needed for kernel modules */ #include <linux/module.h> /* decls needed for kernel modules */ #include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION() */ #include <linux/errno.h> /* EINVAL, ENOMEM */ #include "rtai.h" /* RTAI configuration switches */ #include "rtai_sched.h" #include <rtai_sem.h> MODULE_LICENSE("GPL"); #define ITER 10 #define HIGH 102 /* high priority */ #define MEDIUM 103 /* medium priority */ #define LOW 104 /* low priority */ #define NORMAL_TIME 20000000 /* nanoseconds */ #define LONG_TIME 50000000 /* nanoseconds */ static RT_TASK t1, t2, t3; void priohigh(long arg); void priomedium(long arg); void priolow(long arg); static SEM sync, SEM sembinary;; // semafori int global = 0; void binary(void) int retval; rt_sem_init(&sync, 0); rt_typed_sem_init(&sembinary, 1, RES_SEM FIFO_Q ); retval = rt_task_init(&t1,priohigh, 1, 1024, HIGH, 0, 0); retval = rt_task_init(&t2,priomedium, 2, 1024, MEDIUM, 0, 0); retval = rt_task_init(&t3,priolow, 3, 1024, LOW, 0, 0); retval = rt_task_resume(&t1);retval = rt_task_resume(&t2);retval = rt_task_resume(&t3); while(!(rt_get_task_state(&t1) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t2) & RT_SCHED_SEMAPHORE)); while(!(rt_get_task_state(&t3) & RT_SCHED_SEMAPHORE)); rt_sem_broadcast(&sync);

void priolow(long arg) RTIME startime; int i; rt_printk("resumed TASK #%d (%p) ON CPU %d.\n", arg, &t3, hard_cpu_id()); rt_sem_wait(&sync); for (i=0; i < ITER; i++) rt_sem_wait(&sembinary);/* wait indefinitely for semaphore */ rt_printk("low priority task locks semaphore\n"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_printk("low priority task unlocks semaphore\n"); rt_sem_signal(&sembinary); /* give up semaphore */ rt_printk("...low priority task exited\n"); void priomedium(long arg) RTIME startime; int i; rt_printk("resumed TASK #%d (%p) ON CPU %d.\n", arg, &t2, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano2count(20000000));/* allow time for task with the lowest priority to seize semaphore */ for (i=0; i < ITER; i++) rt_printk("medium task running\n"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + LONG_TIME)); rt_printk("------------------------------------------medium priority task exited\n");

void priohigh(long arg) RTIME startime; int i; rt_printk("resumed TASK #%d (%p) ON CPU %d.\n", arg, &t1, hard_cpu_id()); rt_sem_wait(&sync); rt_sleep(nano2count(30000000));/* lascia tempo ai task di piu bassa priorità */ for (i=0; i < ITER; i++) rt_printk("high priority task trys to lock semaphore\n"); rt_sem_wait(&sembinary);/* wait indefinitely for semaphore */ rt_printk("high priority task locks semaphore\n"); startime = rt_get_cpu_time_ns(); while(rt_get_cpu_time_ns() < (startime + NORMAL_TIME)); rt_printk("high priority task unlocks semaphore\n"); rt_sem_signal(&sembinary); /* give up semaphore */ rt_printk("...high priority task exited\n"); int init_module(void) printk( inizia init_module\n"); rt_set_oneshot_mode(); start_rt_timer(1); binary(); printk("end of init_module\n"); return 0; void cleanup_module(void) return;