Un sistema operativo estremo
Ogni anno, quando si approssima l’inizio del mio corso di Sistemi Operativi, sento il bisogno di illustrare i meccanismi del S.O. con del codice funzionante. Il problema è che mettere il naso dentro il codice di Linux, per dirne una, è difficilissimo anche per me. Anche con l’ausilio di ottimi libri come Understanding the Linux Kernel di Bovet e Casati, nel codice di Linux ci sono troppe complicazioni. Che sono necessarie per realizzare un SO realistico, ma rendono difficile afferrarne il funzionamento.
In alternativa, ci sono un numero di SO giocattolo, pensati per la didattica. L’esempio più famoso è Minix di Tanenbaum, che è una versione molto semplificata e comprensibile di Unix, e gira sui comuni PC Intel. Poi c’è Xinu, che non è Unix, come da acronimo ricorsivo, ma ha lo stesso spirito di Minix: realizzare un SO funzionante in C su hardware comune.
Un’altra categoria sono i SO giocattolo “non realistici”, cioè che non sono in grado di ospitare un completo sistema di sviluppo e compilare sè stessi. Al politecnico di Zurigo c’è Topsy, che è un SO microkernel che gira su processore RISC. Ad Harvard c’è OS/161, che gira su una CPU fittizia (con un assembler ancora più semplice.) Il mio preferito in questa categoria è GeekOS, che ha tutto un percorso didattico associato: ci sono una serie di esercizi che devono essere realizzati (in C e assembly x86), e il tutto gira su Bochs.
Ancora un’altra categoria è quella dei simulatori, che illustrano il funzionamento del SO simulando in maniera più o meno realistica l’hardware. Il più famoso è Nachos.
Alla fine, non ho mai usato nessuno di questi SO didattici, e ho sempre nel profondo l’idea che sarei forse in grado di realizzarne uno che centri il giusto equilibrio di semplicità e completezza. Giusto l’altro giorno stavo tornando su questi pensieri, e mi è venuto in mente che potrei affrontare il problema in stile XP, sfruttando questa mia nuova abilità nel Test Driven Development. L’idea che mi è venuta è vedere se si riesce a fare un simulatore che sia assurdamente semplice.
Ho lanciato Eclipse (ho scelto Java perché i miei studenti già lo conoscono) e ho cominciato a chiedermi come lo testerei questo SO giocattolo. Quello che è saltato fuori è abbastanza strano, sicuramente molto diverso da quello che avrei fatto lavorando nel vecchio metodo non-TDD. Dopo numerosi rimaneggiamenti ho prodotto un paio di test. Il primo dimostra che il SO contiene un task di init, il cui sorgente viene passato al costruttore del SO:
public void testGetInitTask() { String source = "again: JMP again"; InsubOS os = new InsubOS(source); Task init = os.getTask(1); assertEquals(source, init.getSource()); }
Il secondo test verifica il comportamento della chiamata di sistema fork(2):
public void testFork() { String forkOnce = "fork; again: JMP again"; InsubOS os = new InsubOS(forkOnce); assertEquals(1, os.getTaskCount()); os.step(); assertEquals(2, os.getTaskCount()); assertEquals(forkOnce, os.getTask(1).getSource()); assertEquals(forkOnce, os.getTask(2).getSource()); }
Questi test sono semplici schizzi, buttati lì per vedere che effetto mi fa vederli (il codice che li fa passare è semplicissimo.) Non avrò mail il tempo di portare avanti questo progetto, purtroppo. Però quello che vedo mi piace. Penso che mi piacerebbe lavorare sul concetto di sorgente: invece di una stringa di pseudo assembler, mi piacerebbe una costruzione secondo il pattern Composite; qualcosa tipo
new Source(new Syscall("fork"), new Loop(new Noop()))
E sicuramente va aggiunto un concetto di root filesystem. Ragiono in termini Unix-centrici, perché questo è quello che insegno e che mi piace.
Chissà se lo porterò avanti?
]]>