Italia e mondo embedded, una coniugazione che, a prima vista, può sembrare difficile ma che, poi, nella realtà rappresenta una soluzione ottima: con KaeilOS il nostro Paese può certamente offrire un ottimo esempio di ciò che può fare l’industria con l’open source.
Per prima cosa occorre chiarire: KaeilOS è un marchio registrato da Koan e identifica una distribuzione Linux embedded, GPL open source e "royalty free" per applicazioni industriali pensata e realizzata da Marco Cavallini, il proprietario della società italiana. Il sistema messo a punto da Cavallini comprende strumenti di sviluppo e di test appositamente realizzati per il delicato segmento embedded e real-time, oltre alla possibilità di utilizzare tutta la documentazione a supporto dell’iniziativa. Utilizzando KaeilOS si ottiene un completo supporto verso differenti piattaforme hardware: dalla serie x86 fino all’ARM, passando per il mondo PowerPC. Non solo: Koan, società che ha realizzato il progetto e di proprietà di Marco Cavallini, mette a disposizione diversi BSP pronti all’uso per differenti piattaforme hardware.
Sistemi in tempo reale
I sistemi definiti come real-time hanno la caratteristica di dover rispondere alle sollecitazioni esterne in un tempo definito, o conosciuto, a priori e ben determinato. In questo caso occorre chiarire un concetto che a volte è fonte di ambiguità; in effetti non è importante, in un sistema di questo tipo, rispondere ad un evento in un tempo stretto, ad esempio nell’ordine dei microsecondi, perché la risposta è in relazione all’ambiente e all’applicazione utilizzata. In sostanza, non esiste nessuna relazione tra la durata dell’intervallo che intercorre tra ricezione dello stimolo e risposta; in effetti, un sistema in tempo reale non è necessariamente veloce, ma è fondamentale che sia deterministico, ossia che la risposta arrivi entro tolleranze ben precise e note a priori. Ecco perché un sistema Real-Time non è sinonimo di “sistema veloce”: un processo Real-Time deve terminare rispettando i vincoli temporali (le sue deadline) stabiliti in modo tale che la sua esecuzione sia in grado di rispondere alle sollecitazioni esterne. Non solo, un sistema di questo tipo deve anche essere in grado di prevedere se i processi che lo schedulatore metterà in esecuzione saranno o meno in grado di rispettare le loro deadline. È chiaro che diversi fattori esterni possono incidere sul determinismo, tanto che alcuni hanno osservato che le caratteristiche architetturali dell’elaboratore utilizzato o il linguaggio di programmazione con il sistema operativo possono, di certo, influenzare il determinismo. Per ovviare a questa particolare restrizione si sono definite soluzioni architetturali innovative in grado di offrire processori con una bassa latenza di risposta agli interrupt con linguaggi di programmazione in grado di assicurare un maggiore controllo sui vincoli temporali. Accanto ad una soluzione di tipo prettamente fisico (processore), esiste anche un approccio di tipo software coinvolgendo il sistema operativo utilizzato. In questo caso diventa importante una gestione corretta e mirata di alcune funzionalità che, in questo contesto, diventano importanti: la gestione dei processi e delle interruzioni, la sincronizzazione dei processi e la mutua esclusione fra le risorse condivise. In un ambito di questo tipo si preferisce, di solito, partire dallo standard Posix per sistemi operativi di tipo general purpose prevedendo delle possibili estensioni specifiche per applicazioni o ambiti applicativi di tipo Real-Time. In passato, la maggior parte dei sistemi embedded che operavano secondo modalità real-time usavano un sistema operativo di tipo proprietario realizzati con l’unico obiettivo di soddisfare le esigenze di una particolare applicazione e difficilmente inquadrabili in uno standard condivisibile. Al giorno d’oggi, l’approccio è totalmente cambiato perché, in virtù di esigenze economiche, diventa necessario utilizzare sempre più soluzioni condivisibili e a basso costo. A questo riguardo la Figura 1 pone in evidenza la road map dell’evoluzione dell’interfaccia POSIX. Si ricorda che POSIX 1003.1° definisce lo standard per le interfacce di base e POSIX 1003.1c si occupa di standardizzare la gestione dei thread. Inoltre, sono state definite estensioni per sistemi real-time con POSIX 1003.1b, 1003.1d, 1003.1j: la variante 1003.1b è l’unico comunemente implementato.
Hard e soft real time
La letteratura pone in evidenza una netta distinzione tra hard e soft real-time. In effetti, la distinzione, a prima vista, può sembrare impercettibile: nei sistemi di tipo hard si richiede un rispetto rigido dei vincoli di precisione temporale, mentre in quelli soft, di solito, si limita a rispettare, in modo statistico, i vincoli previsti nell’applicazione. Nel primo caso mancare una scadenza significherebbe invalidare il funzionamento dell’intero sistema, mentre nell’altro caso non rispettare i vincoli imposti comporterebbe una degradazione dell’applicazione. In quest’ultimo caso, la degradazione può essere tollerata considerando i requisiti prestazionali del sistema. Ecco perché, a volte, quando si tenta di dare una descrizione di questi sistemi, si cerca di dare particolare risalto sui requisiti temporali e su una maggiore tolleranza.
Linux Real Time
Linux non nasce come sistema real-time; in effetti, con il kernel di Linux, e fino alla versione 2.4, possiamo senza dubbio ricordare che sono state implementate alcune estensioni real-time previste dallo standard POSIX, ma insufficienti per garantire la corretta gestione di processi real-time. Successivamente, con la versione 2.6, si è cercato di portare al kernel alcune caratteristiche più adatte ai sistemi real-time (soft real-time). In effetti, possiamo ricordare che i processi presenti nel kernel di Linux son divisi in due moduli funzionali: user e kernel mode. In User mode, l’esecuzione dei processi avviene in modalità di esecuzione dei programmi utente e sono utilizzate delle politiche si sicurezza per evitare l’accesso a zone critiche del sistema. Viceversa, il Kernel mode rappresenta la modalità di esecuzione privilegiata e permette di accedere incondizionatamente a tutte le risorse presenti nel sistema. Nello scheduling di Linux è possibile effettuare una preemption sui processi utente e, ad ogni programma in esecuzione, è associata una politica di scheduling e una priorità. In una gestione di tipo tradizionale, in Linux a ogni processo viene assegnato un quanto di tempo massimo di uso della CPU ed una priorità dinamica data dalla somma di un valore di base e di un valore che decresce all’aumentare del tempo di CPU utilizzato. In un sistema di questo tipo viene fatto un aggiornamento dinamico della priorità allo scopo di garantire un’equa ripartizione della CPU tra tutti i processi. In un sistema di tipo real-time Linux la politica di schedulazione adotta un sistema di tipo round robin o FIFO. Nel primo caso, per ogni processo è definito un valore di priorità statica ed un periodo di tempo massimo durante il quale è assegnato alla CPU (time quantum). La risorsa di calcolo è assegnata al processo a priorità elevata ed il processo in esecuzione perde l’uso della CPU se termina, si sospende o se c’è un processo pronto a priorità maggiore o dopo aver esaurito il proprio limite temporale. Ogni volta che un processo termina, questo deve essere inserito in una lista dei processi pronti con il suo livello di priorità. In caso di preemption da parte di un processo più prioritario, è posto in testa alla lista dei processi pronti al suo livello di priorità. In alternativa, in un sistema di tipo FIFO un processo ha solo un valore di priorità statica e in caso di processi al medesimo livello di priorità questi sono accodati secondo l’istante di attivazione e valgono le stesse considerazioni della politica round robin. È doveroso precisare che con Linux lo scheduler non ha nessuna conoscenza dei requisiti temporali dei processi e l’algoritmo di scheduling OTHER ha una durata imprevedibile (kernel 2.4) ed è in relazione al numero dei processi attivi nel sistema. Gli algoritmi di scheduling di tipo “realtime” offrono politiche insufficienti alla gestione di un sistema RT classico. Non solo, in Linux 2.4 non è nemmeno preemptable quando si sta eseguendo in uno spazio kernel: un processo funzionante in kernel mode (ad esempio, una system call) non può subire preemption ed il cambio di contesto può avvenire solo al termine dell’esecuzione in kernel mode. Tutto questo comporta, per la versione 2.4, politiche di scheduling insufficienti con un’alta latenza: kernel non preemptable con periodo minimo di attivazione dell’algoritmo di scheduling di 10 ms che ne consegue un indeterminismo della latenza di scheduling. Al contrario, la versione 2.6 del kernel apporta sostanziali vantaggi; in effetti, la versione dispone di un algoritmo di scheduling ottimizzato: l’overhead dovuto alle operazioni di scheduling è determinabile a priori e non è dipendente dal numero di processi attivi. La frequenza interna del clock è di 1000 Hz, ovvero il periodo minimo di esecuzione dello scheduler pari a 1 ms e il kernel risulta del tipo preemptable. Non solo, è anche possibile inserire dei punti di preemption nel kernel in cui si può eseguire lo scheduling. In sostanza, nella versione 2.6 si è migliorato il supporto verso i processi real-time anche se rimane il vincolo di non poter essere utilizzato per scopi dove è necessario rispettare forti vincoli temporali: ecco perché diventa necessario estendere le possibilità del kernel di Linux attraverso altre possibilità. A questo proposito KaeilOS intende proporsi come una soluzione alternativa alle diverse distribuzioni attualmente presenti nel segmento embedded. Esistono diverse varianti di Linux, ognuno con caratteristiche particolari: da una parte c’è chi pensa di rendere il kernel di Linux full preemptable e deterministico, mentre dall’altra c’è chi pensa di inserire una sorta di kernel real-time che gestisce il kernel Linux come un processo a bassa priorità. Per rispondere a queste esigenze esistono sul mercato diverse versioni di Linux con particolari estensioni in realtime come RTAI del politecnico di Milano e Xenomai, fino alla possibilità di applicare alla singola distribuzione le patch RT Preemption. Koan suggerisce, al contrario, la sua variante: KaeilOS con kernel 2.6 a bassa latenza con le estensioni in tempo reale realizzate da Ingo Molnar e Thomas Gleixner. In realtà, l’offerta di Koan è ben più ampia perché, se da una parte offre una soluzione basata su patch con RT Preemption, la proposta di Koan offre anche le estensioni appositamente realizzate in ambito RTAI e Xenomai. In effetti, per KaeilOS le estensioni real-time sono opzionali e possono essere inserite adattando le singole patch alla specifica applicazione.
KTX: configurare KAEILOS
Il kernel real-time di Koan può essere facilmente configurato per ogni applicazione al fine di sfruttare le diverse prerogative. Attraverso il tool KTX, infatti, è possibile selezionare in maniera modulare ogni differente componente, inclusa la libreria C, le estensioni RTAI e real-time con Xenomai, la versione del kernel, la possibilità di selezionare i diversi strumenti di verifica e debug (basato su GDB, gdbserver, crossgdb, ksymoops e strace), il filesystem, la toolchain di lavoro (gcc, glibc e binutils) e le opzioni target (Figura 2). Non solo: con il tool di configurazione è anche possibile impostare la selezione della variante uClibc allo scopo di utilizzare piattaforme hardware senza MMU o agire sulle varie opzioni di networking. La procedura di configurazione del kernel è, in sostanza, un’operazione estremamente flessibile che consente, senza per questo conoscere in maniera dettagliata Linux, di impostare una propria variante che tenga conto dei requisiti di sviluppo.