E mumolo deei mumolo@units it
Download
1 / 63

Programmazione RTAI - PowerPoint PPT Presentation


  • 102 Views
  • Uploaded on

E.Mumolo, DEEI [email protected] Programmazione RTAI . Programmazione in RTAI. Approccio RTAI: Uno schedulatore Real Time rimpiazza lo schedulatore di Linux Intercetta gli interrupt (time e dispositivi) Esegue il codice di servizio degli interrupt in tempo reale

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Programmazione RTAI ' - joie


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
E mumolo deei mumolo@units it

E.Mumolo, DEEI

[email protected]

Programmazione RTAI


Programmazione in 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 rtai1
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

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 rtai2
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 rtai3
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 rtai4
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 rtai5
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 rtai6
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 rtai7
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 rtai8
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 rtai9
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 rtai10
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 rtai11
Programmazione in RTAI moduli del kernel */

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 rtai12
Programmazione in RTAI moduli del kernel */

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
Programmazione in RTAI: moduli del kernel */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> moduli del kernel */

#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’ moduli del kernel */

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) moduli del kernel */

{

int delay_left = delay_count; /* decrementato ad ogni ciclo */

unsigned char sound_byte, toggle = 0;

while (1) {

if (delay_left > 0) { //ritardo restante?

delay_left--;

} else {

sound_byte = inb(SOUND_PORT);

if (toggle) { sound_byte = sound_byte | SOUND_MASK; }

else { sound_byte = sound_byte & ~SOUND_MASK; }

outb(sound_byte, SOUND_PORT);

toggle = ! toggle;

delay_left = delay_count; /* ricarico il ritardo*/

}

rt_task_wait_period();

}

/* non arriviamo mai qui */

return;

}

void delay_function(int arg)

{ while (1) { delay_count++; rt_task_wait_period(); }

/* non arriviamo mai qui */

return;

}


void cleanup_module(void) moduli del kernel */

{

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 rtai13
Programmazione in RTAI moduli del kernel */

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 rtai14
Programmazione in RTAI moduli del kernel */

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> moduli del kernel */#include <linux/kernel.h>#include <linux/module.h>#include <rtai.h>#include <rtai_sched.h>#include <rtai_sem.h>MODULE_LICENSE("GPL");#define STACK_SIZE 2000#define EXECTIME 400000000#define RR_QUANTUM 10000000#define NTASKS 3#define PRIORITY 100static SEM sync, RT_TASK tasks[NTASKS], int switchesCount[NTASKS];static void fun(long indx) //funzione eseguita dai task { RTIME starttime, endtime;; rt_printk("Resume task #%d (%p) on CPU %d.\n", indx, &tasks[indx], hard_cpu_id()); rt_sem_wait(&sync); rt_printk("Task #%d (%p) inizia on CPU %d.\n", indx, &tasks[indx], hard_cpu_id());

starttime = rt_get_cpu_time_ns(); //esegue per 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) moduli del kernel */{ 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 rtai15
Programmazione in RTAI moduli del kernel */

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> moduli del kernel */

#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 rtai16
Programmazione in RTAI switches

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

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 tempo passato

{

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

{

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
Schedulazione EarliestDeadlineFirst (EDF) specifica

#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
EDF (cont.) specifica

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

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

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

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

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

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 specifica

#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) specifica

{

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 specifica

#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) specifica

{

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

{

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

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

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

{

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) modules */

{

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 ipc7
Programmazione in RTAI: IPC modules */

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 daRTAI


Programmazione in rtai ipc8
Programmazione in RTAI: IPC modules */

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
IPC in RTAI: memoria condivisa modules */

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
IPC in RTAI: semafori modules */

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 rtai17
Programmazione in RTAI modules */

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

}


ad