Inferno
Un sistema operativo compatto per costruire sistemi distribuiti multi-piattaforma
- Panoramica
- Installare e usare Inferno
- Limbo
- Styx
- Note
Panoramica
Inferno e' un sistema operativo sviluppato originariamente dalla Lucent Technologies presso i Laboratori Bell e successivamente da Vitanuova (www.vitanuova.com). La sua peculiarita' e' che puo' essere eseguito in modo nativo su piccoli dispositivi oppure come processo utente in ambienti Linux/Unix/NT/Plan9. Questo, unito al supporto per piu' architetture (Intel, SPARC, MIPS, PowerPC, ARM e altre), garantisce la portabilita' delle applicazioni di Inferno su piattaforme diverse tra loro.
Altra caratteristica che lo contraddistingue e' l'inclusione di un sistema di namespace, che permette di costruire per ogni processo una visione personale delle risorse locali e remote, dove per risorse si intendono files, directory, dispositivi hardware. Una volta creato il proprio namespace, e trattando quindi le risorse collegate esattamente come se fossero locali, diventa banale scrivere applicazioni distribuite, in Limbo o in shell scripting.
Limbo e' il linguaggio di programmazione di Inferno ed e' l'unico ad avere un compilatore all'interno della distribuzione. E' un linguaggio ad oggetti, permette programmazione concorrente e comprende un set completo di funzioni di libreria divise per moduli.
Inferno e' distribuito con due licenze separate: una compatibile con la definizione di Free Software della FSF, per chi voglia sviluppare software libero con Inferno, e una commerciale, a pagamento, per chi intenda sviluppare applicazioni che non possano essere definite Free Software.
I dettagli sulle licenze d'uso di Inferno si trovano all'indirizzo www.vitanuova.com/inferno/licence.html
indice
Installare ed usare Inferno
La quarta edizione di Inferno e' reperibile presso www.vitanuova.com/inferno/net_download4T.html.
L'archivio inferno.tgz e' indipendente dalla piattaforma, mentre a seconda del sistema operativo su cui girera' Inferno bisogna scegliere l'archivio adatto tra Debian, FreeBDS, Irix, Linux, MacOSX, Nt, Plan9 e Solaris.
Una volta scaricati e decompressi i due file va lanciato lo script di installazione appropriato dalla directory /install specificando quale sara' la root directory di Inferno.
Vediamo l'esempio su un sistema GNU/Linux (l'archivio Linux.tgz e' specifico per Red Hat, per le altre distribuzioni e' preferibile Debian.tgz)
user@host:/$ cd /inferno
user@host:/$ ls
Debian.tgz
inferno.tgz
user@host:/$ tar -xzvf Debian.tgz inferno.tgz
user@host:/$ ./install/Debian-386.sh /inferno
user@host:/$ ls
acme dev Hp keydb man net prof tmp
appl dis icons lib mkconfig net.alt prog usr
chan doc include LICENCE mkfiles NOTICE README.html wrap
CHANGES env inferno.tgz Linux mnt Nt services
Debian fonts install locale module nvfs Solaris
Debian.tgz FreeBSD Irix mail n Plan9
Per comodita', ecco uno script per la bash che scarica e installa Inferno per GNU/Linux, creando l'eseguibile inferno che lancia la macchina virtuale con i parametri corretti.
inferno_install.sh
Per lanciare la macchina virtuale:
user@host:/$ ./Debian/386/bin/emu -r/inferno
a questo punto, se tutto e' andato bene, viene presentato il prompt della shell di Inferno, chiamata rc:
;
Avviando Inferno in sola modalita' console l'utente e' lo stesso che ha lanciato il comando emu. Per aggiungere utenti e' sufficiente creare una cartella col nome dell'utente dentro /usr (analoga alla cartella home dei sistemi unix-like.
; mkdir /usr/utente
e' possibile usare il sistema da console, semplicemente digitando i comandi, oppure lanciare l'ambiente grafico wm con il comando:
; wm/wm
per accedere all'autenticazione grafica (l'unico user presente e' inferno) il comando e':
; wm/wm wm/logon
Cliccando sul pulsante in basso a destra si apre un menu con le funzioni principali di inferno.
La voce Shell apre rc, la shell dei comandi di Inferno.
Gli eseguibili hanno estensione .dis; per avere un'idea dei programmi che di trovano nella distribuzione si puo' guardare al contenuto della cartella /dis:
; ls /dis
altre cartelle interessanti sono:
/appl
contiene i codici sorgenti degli applicativi (file .b)
/doc
contiene varia documentazione in formato postscript
/module
qui si trovano i moduli di limbo presenti con la distribuzione
/net
qui viene creata una sotto-directory per ogni connessione di rete effettuata, ognuna contenente file utili per la gestione della connessione.
/usr
contiene le home directory degli utenti
L'applicazione edit e' l'editor di testi di Inferno. Come la altre applicazioni e' molto spartana, ma funzionale.
Per programmare in Inferno e' possibile scrivere codice Limbo o script per la shell, mentre non sono disponibili compilatori o interpreti per altri linguaggi. Esiste un compilatore Limbo per GNU/Linux, Acheron, ma e' ancora in fase di sviluppo. La pagina di Acheron e' sourceforge.net/projects/acheron-l/
I file di script per la shell sono semplici file di testo contenenti i comandi per la shell. Uno script va lanciato con il comando sh:
; sh test.sh
Fatti non foste a viver come bruti
Con il file test.sh contenente la sola riga:
echo "Fatti non foste a viver come bruti"
Per una documentazione completa sui comandi per la shell di Inferno si puo' digitare:
; man sh
I file Limbo, invece, per essere eseguiti hanno bisogno di essere compilati (o piu' precisamente semi-compilati). Partendo dal file (o dai file) sorgente con estensione .b bisogna digitare:
; limbo hello.b
Se la compilazione va a buon fine (non ci sono errori) viene generato un file eseguibile con estensione .dis. Per lanciare l'eseguibile digitare semplicemente il nome del file generato, senza estensione.
; ls
hello.b
hello.dis
; hello
Hello World!
indice
Limbo
La documentazione ufficiale di Limbo si trova presso:
www.vitanuova.com/inferno/papers/limbo.html
Limbo e' un linguaggio di programmazione ad oggetti fortemente tipato. Il compilatore Limbo produce byte-code semicompilato, da eseguire sulla macchina virtuale Inferno. Tra la sue caratteristiche comprende:
- un set esteso di tipi di dati primitivi: liste, tuple, array, canali, strutture tipo C, moduli. e' fortemente modularizzato e l'ambiente di sviluppo comprende un insieme piuttosto ampio di moduli di libreria.
- gestione della programmazione concorrente: chiamando una funzione con il costrutto:spawn myfuncion();
la funzione e' eseguita in un thread parallelo e i moduli wait (interfaccia al file wait nel namespace del processo) e lock (semafori binari) offrono semplici meccanismi di sincronizzazione.
- richieste Styx: le funzioni mount, bind, unmount gestiscono la creazione del namespace; le richieste avvengono con open, create, read, write, stream effettuano operazioni sulle risorse (tipicamente leggendo e scrivendo stringhe su file).
Anche altre funzioni utilizzano Styx, in modo trasparente al programmatore: le chiamate per stabilire connessioni di rete dial, announce e listen al loro interno in effetti utilizzano il contenuto di /net, scrivendo ad esempio sul file /net/tcp/1/ctl per stabilire una connessione o leggendo da /net/tcp/1/data per ricevere dati.
Vediamo le particolarita' di Limbo piu' nel dettaglio.
- Le liste
In Limbo abbiamo una gestione integrata del tipo lista. Possiamo aggiungere e togliere elementi ad una lista con l'operatore :: e con i comandi hd e tl
- Le tuple
E' possibile fare ritornare ad una funzione piu' di un valore, usando le tuple.
Se ad esempio una funzione e' definita in questo modo:
getconf():(string, string)
{
[...]
return (stringA, stringB);
}
Questa funzione ritornera' due stringhe. La chiamata della funzione sara' ad esempio:
(RetStringA, RetStringB) := getconf();
- I channel
I channel sono l'equivalente delle named pipe dei sistemi *nix. Sono molto utili per fornire meccanismi di sincronizzazione e di comunicazione inter-processo.
Possono anche essere usate per gestire l'interfaccia grafica, che si sviluppa in Tcl/Tk. Per la comunicazione tra Limbo e Tcl si usando i channel. Esempio:
com := chan of string;
tk->namechan(t, com, "com");
[...]
#Creaimo nell'interfaccia grafica un bottone
tk->cmd(t, "button .btnExit -text Esci -command {send com exit}");
#Come si puo' vedere, attraverso il comando send viene spedita una stringa dal
namespace di Tcl a quello di limbo, usando il channel com
#Ora in com, utilizzabile in Limbo, avremo il valore "exit" accodato ogni volta
che viene premuto il pulsante
- I moduli
Limbo viene fornito con una vasta libreria suddivisa in moduli. I moduli non sono altro che file, uno con estensione .m, e un altro con estensione .b.
Il file m contiene la dichiarazione di tutte le funzioni pubbliche, ossia che possono venire invocate dall'esterno del modulo.
Il file b contiene invece il codice vero e proprio del modulo.
Ad esempio, se dal nostro programma vogliamo caricare il modulo predefinito Sys, sara' sufficiente scrivere:
sys := load Sys Sys->PATH;
Analizziamo in dettaglio il significato di questa riga di codice.
Viene creato un oggetto sys, che sara' quello che potremo poi utilizzare . Viene caricato il modulo Sys e andiamo a specificare il PATH in cui si trova il file .b, contenente il sorgente. PATH e' una variabile pubblica che viene specificata nel file m. Ne consegue che se spostiamo il file b in una directory diversa senza modificare il file m, indicando il nuovo path, sys non viene piu' caricato.
A questo punto, possiamo usare l'oggetto sys e le funzioni pubbliche che ci sono state messe a disposizione.
Ecco un semplice esempio:
sys->print("Hello everybody!\n");
E' anche possibile creare un proprio modulo, che verra' poi usato a proprio piacimento all'interno di altre applicazioni.
Il formato del file m sara' il seguente:
nome_modulo: module{
PATH: con path_string;
nome_funzione: fn(args: tipo, [...]): (return_arg: tipo, [...]);
nome_variabile: tipo;
};
Invece, il file b conterra' l'implementazione di ogni funzione dichiarata nel file m. E' possibile anche sviluppare funzioni non dichiarate nel file m. Queste funzioni saranno private, ossia possono essere chiamate solo all'interno del modulo, a differenza delle altre che vengono definite pubbliche
- Gestione della programmazione concorrente
In Limbo e' implementata inoltre la gestione della programmazione concorrente. Per lanciare un nuovo thread e' sufficiente usare la funzione spawn.
La sintassi e' questa:
spawn nome_funzione(arg, [...])
L'istruzione spawn crea un nuovo processo che, ad eccezione del suo stack, condivide la memoria con il processo padre. Lo scheduler dei processi e' di tipo preemptive. Ogni sincronizzazione tra i processi e' gestita attraverso i channels.
Il modulo Lock, fornito con la libreria standard di Limbo, fornisce la mutua esclusione usando un semaforo. Innanzitutto, dopo avere caricato il modulo e creato un'istanza dell'oggetto lock, andra' chiamata la funzione init:
lock->init();
A questo punto, potremo creare semafori, usando:
lock->nuovo_sem.new();
e avremo le istruzioni equivalenti alle classiche p e v della letteratura:
lock->nuovo_sem.obtain();
lock->nuovo_sem.release();
indice
Styx
La documentazione ufficiale su Styx si trova presso:
www.vitanuova.com/inferno/papers/styx.html
Nello sviluppo di Inferno, come derivato di Plan9, e' stata mantenuta l'idea dei sistemi *nix che "tutto sia un file", anzi il concetto e' stato esteso a tutti i tipi di risorse, come ad esempio le connessioni di rete. L'accesso ad una risorsa avviene quindi semplicemente tramite il filesystem. Un namespace e' un insieme di risorse, remote e locali, che appaiono al proprio processo come un filesystem gerarchico.
Il "collante" che tiene unite le diverse risorse e' il protocollo Styx. Derivato da 9P, il protocollo che svolge la stessa funzione su Plan9, Styx si appoggia su vari protocolli di trasporto, come TCP/IP o ATM, ma anche su protocolli di livello link ed e' composto da 13 tipi di messaggi per gestire navigazione nel filesystem, lettura e scrittura e modifica dello stato di files.
Styx fornisce come API le funzioni mount, bind e unmount, come comandi per la shell e come modulo per Limbo. Mount collega il processo alla risorsa interessata, bind la aggiunge al namespace, unmount termina il collegamento. Grazie a questo sistema le applicazioni distribuite hanno una struttura del tipo:
- comandi mount e bind, creazione del namespace utilizzato dal processo.
- operazioni sul namespace, visto come filesystem ed acceduto tramite chiamate standard per tutti i tipi di risorse.
Ad esempio, un terminale che accede ad una macchina remota puo' eseguire un codice del genere:
mount 192.168.0.99 /server
bind /server/dev/keyboard /dev/keboard
bind /server/dev/draw /dev/draw
bind /server/dev/pointer /dev/pointer
e successivamente continuera' ad usare tastiera, mouse e schermo collegati alla macchina remota.
Vediamo un esempio concreto dell'uso di Styx.
Ecco un piccolo server (in Limbo) che non fa altro che accettare connessioni tcp sulla porta 9999 ed esportare una cartella.
1: implement Server;
2: include "draw.m";
3: include "sys.m";
4: sys: Sys;
5: Server: module{
6: init: fn(ctxt: ref Draw->Context, argv: list of string);
7: };
8: init (ctxt: ref Draw->Context, argv: list of string){
9: sys = load Sys Sys->PATH;
10: result: int;
11: listening, connection: Sys->Connection;
12: (result, listening) = sys->announce("tcp!localhost!9999");
13: while(1){
14: (result, connection) = sys->listen(listening);
15: fd_data := sys->open(connection.dfd, Sys->ORDWR);
16: sys->print("A client has connected\n");
17: sys->export(fd_data, "exportme", Sys->EXPASYNC);
18: }
19: }
Analizziamo il codice:
12: (result, listening) = sys->announce("tcp!localhost!9999");
14: (result, connection) = sys->listen(listening);
announce e listen sono le funzioni per stabilire connessioni di rete lato server, analoghe rispettivamente a listen e accept della libreria socket (che in Limbo non e' presente).
Listen e' all'interno di un ciclo infinito, in modo che il server abbia il comportamenteo di un demone e non termini dopo la prima connessione.
15: fd_data := sys->open(connection.dfd, Sys->ORDWR);
Questa va spiegata in dettaglio. Quando in Inferno si instaura una connessione di rete (tcp, udp o di altro tipo) viene creata una directory nel path /net/tcp (o /net/udp etc.) contenente al suo interno vari file di testo, tra cui il file data.
A questo punto per scrivere e leggere dal canale di comunicazione e' sufficiente accedere al file data, di cui connection.dfd e' il riferimento. Per questo bisogna aprire esplicitamente il file con una chiamata a sys->open.
Bisogna inoltre ricordare che sul canale di comunicazione non e' possibile trasferire contemporaneamente richieste Styx e stringhe di altro tipo, poiche' la gestione del protocollo avviene internamente al sistema e potrebbero generarsi problemi di concorrenza.
17: sys->export(fd_data, "exportme", Sys->EXPASYNC);
Stabilita la connessione, il server esporta la cartella chiamata exportme (il percorso in questo caso e' relativo) sul canale appena aperto (fd_data).
Il flag EXPASYNC indica che la gestione delle richieste Styx avverra' in un thread separato, concorrentemente all'esecuzione del programma. Settandola invece a EXPWAIT l'esecuzione si blocchera' fino a che tutte le richieste del client non siano state soddisfatte, ovvero fino alla sua disconnessione.
Ora, col server appena visto in esecuzione ad esempio su una macchina chiamata dante, supponendo che sia presente una cartella chiamata exportme con all'interno i file file1 e file2, un client che voglia montare la cartella remota puo' digitare dalla shell:
; mkdir server
; ls server
; mount -A tcp!dante!9999 server
; ls server
file1
file2
; unmount server
L'opzione -A specifica di non usare l'autenticazione (prevista a livello di protocollo).
Ovviamente l'utilizzo di Styx non si ferma qui. Ricordando che in Inferno ogni risorsa (periferiche hardware, connessioni di rete, servizi di sistema) viene rappresentata come un file in un filesystem gerarchico le possibilita' di utilizzo si moltiplicano.
indice
Note
Questa documentazione e' stata scritta da Valerio Basile, Marco Bertini, Massimiliano Donati e Marica Landini come progetto per il corso di Sistemi Operativi all'Universita' di Bologna.
Durante il lavoro abbiamo sviluppato una applicazione di file sharing per Inferno chiamata Beatrice. Il programma e' composto da un modulo per Limbo, un server ed un'interfaccia grafica per il client. Beatrice e' software libero, sono quindi graditi commenti al codice, modifiche e redistribuzione del codice.
pagine man del modulo Beatrice
codice sorgente
screenshot
indice
gipoco.com
is neither affiliated with the authors of this page or responsible
for its contents. This is a safe-cache copy of the original web site.
gipoco.com
is neither affiliated with the authors of this page nor responsible
for its contents. This is a safe-cache copy of the original web site.