Ingresso/uscita e driver
Nella pagina dedicata al file system abbiamo imparato a vedere il disco come un armadio ordinato, con i suoi cassetti, le sue etichette e i suoi indici, e abbiamo capito come il sistema operativo trasformi una lastra metallica o un chip di memoria in un albero di directory e di file dotati di nomi. C'è però una questione che abbiamo accuratamente rimandato, e cioè che prima ancora di sapere dove un file si trova, qualcuno deve muovere fisicamente qualcosa, deve far girare un piatto, accendere un motore o spostare un fascio di elettroni, perché i dati che il processore tratta come numeri dentro la memoria vivono in realtà da qualche altra parte, sopra oggetti che hanno parti che si muovono, si scaldano e invecchiano. In questa pagina scendiamo proprio da quel gradino, quello che separa il mondo puro e velocissimo del processore dalla cucina rumorosa e meccanica delle periferiche, e impareremo come il sistema operativo riesca a dare ordini a strumenti tanto diversi senza impazzire, con la promessa che a fine lettura guarderemo la tastiera e il disco come oggetti finalmente compresi.
Aiutiamo gli occhi con un'immagine che ci accompagnerà fino all'ultima riga. Il sistema operativo somiglia a un direttore d'orchestra che ha in testa la partitura, sa esattamente quale nota deve suonare e quando, eppure non emette alcun suono con le proprie mani, perché il suono lo producono gli strumentisti, il violinista, il timpanista, il flautista, ognuno con il proprio strumento, la propria lingua e i propri tempi. Le periferiche, dal disco rigido allo schermo, dalla tastiera alla stampante, sono gli strumentisti dell'orchestra, e il capitolo che stiamo per raccontare spiega proprio questo mestiere, e cioè come il direttore comunichi con ciascun musicista, come faccia a sapere quando uno di loro ha finito il proprio assolo e perché a volte preferisca incaricare un assistente di sorvegliare l'intera sezione dei fiati mentre lui si occupa dei violini.
Cominciamo dagli strumenti. Una periferica di ingresso e uscita, dove per ingresso si intende tutto ciò che entra nella macchina e per uscita tutto ciò che ne esce, è nella vita reale un oggetto elettromeccanico o elettromagnetico, cioè un oggetto che mischia circuiti elettronici a motorini, bracci, piatti rotanti, martelletti, bobine o cristalli, e proprio per questo è lentissimo se paragonato al processore che l'ha appena comandato. Un tasto premuto viaggia a una manciata di byte al secondo, un mouse a poche centinaia, un disco a centinaia di milioni, e il libro ci mostra una tabella in cui le velocità si allontanano di nove ordini di grandezza, il che significa che tra il tasto più pigro e il bus più veloce corre un abisso pari a quello che corre fra il passo di una lumaca e il razzo, e il software deve servirli tutti con la stessa aria tranquilla.
Per reggersi in questo zoo, la prima cosa che il sistema operativo fa è dividere le periferiche in due famiglie, e la divisione conta ancora oggi nel modo in cui sono organizzati Linux e i suoi cugini. I dispositivi a blocchi memorizzano l'informazione in blocchi di dimensione fissa, ciascuno dotato del proprio indirizzo numerico, e la proprietà decisiva è che ogni blocco si può leggere o scrivere indipendentemente da tutti gli altri, come le caselle di un archivio dotate ciascuna di un numero progressivo. I dischi rigidi, i dischi ottici e le chiavette appartengono a questa famiglia. I dispositivi a caratteri invece offrono o accettano un fiume continuo di caratteri senza alcuna struttura a blocchi, senza indirizzi e senza possibilità di saltare, e qui trovano posto tastiere, mouse, stampanti e schede di rete, che somigliano più a un nastro che scorre che a un archivio di caselle.
La classificazione, com'è giusto che sia, ha i suoi angoli sfuggenti, e conviene guardarli subito per non farci ingannare. I nastri magnetici da backup contengono blocchi, quindi in teoria rientrerebbero nella prima famiglia, eppure raggiungere un blocco a metà nastro richiede di riavvolgere tutto e leggere da capo, il che li avvicina più alla pazienza di un fiume che all'accesso diretto. Gli orologi non sono né l'una né l'altra cosa, perché non memorizzano nulla e non emettono caratteri, e fanno soltanto suonare una campanella a intervalli regolari. Le due classi servono comunque, perché permettono di costruire il software in modo indipendente dal dispositivo, così che il file system lavori sempre con blocchi astratti e lasci ai piani inferiori il compito di parlare il dialetto vero di ogni macchina, e questo è un principio che ci accompagnerà per tutta la pagina.
Chi parla questi dialetti è, per ogni periferica, un piccolo computer nascosto dentro o accanto ad essa, che il libro chiama controllore e che altri chiamano adattatore. L'unità di ingresso e uscita si divide in due metà, una meccanica che è il dispositivo vero e proprio e una elettronica che è il controllore, e sui computer personali il controllore vive spesso come un chip sulla scheda madre oppure come una scheda a sé che si infila nello slot di espansione, con un connettore sul retro dove si avvita il cavo che va al dispositivo. Un singolo controllore sa guidare anche due, quattro o otto dispositivi identici insieme, e quando il punto di contatto fra controllore e dispositivo segue uno standard riconosciuto, quello ufficiale di un ente internazionale o quello di fatto nato dal mercato, aziende diverse possono costruire dischi o schede che si montano a vicenda come fossero usciti dalla stessa fabbrica.
Il mestiere del controllore è togliere al sistema operativo ogni preoccupazione elettrica, e un esempio vale più di una definizione. Un disco, guardato da vicino, consegna soltanto un fiume di bit uno dopo l'altro, che comincia con un preambolo scritto in fabbrica nel quale stanno il numero di cilindro, il numero di settore e la dimensione del blocco, continua con i quattromilanovantasei bit dei dati e si chiude con un codice di correzione degli errori, e il controllore deve assemblare quei bit uno a uno dentro un proprio buffer interno, verificare che il codice confermi la salute dei dati e soltanto allora consegnare il blocco alla memoria principale. Lo schermo funziona allo stesso modo, perché il controllore del monitor riceve i byte che rappresentano i caratteri o i pixel e genera lui, paziente, i segnali che orientano la luce di ogni punto, altrimenti il programmatore dovrebbe comandare a mano il campo elettrico di ogni singolo puntino, fatica che non auguriamo nemmeno al peggiore dei nemici.
Per comandare questi impiegati esemplari, la CPU ha bisogno di due strade, una per dare
ordini e una per ricevere notizie, e il libro le chiama registri di controllo e buffer di
dati, che insieme formano le porte di ingresso e uscita, port in inglese. La domanda
tecnica è come la CPU indirizzi queste porte, e la storia ha dato due risposte. La prima,
usata dai primi grandi calcolatori, assegna a ogni registro un numero di porta e offre
istruzioni speciali che si chiamano IN e OUT per leggerle e
scriverle, tenendo la memoria e le porte in due mondi separati, tanto che la cella numero
quattro e la porta numero quattro sono due entità che non si incontrano mai. La seconda
risposta, introdotta dal mitico PDP-11, appoggia tutti i registri di controllo dentro lo
spazio degli indirizzi di memoria, e questa tecnica si chiama ingresso e uscita mappato in
memoria, memory-mapped I/O.
Questa seconda scelta, quella adottata dai processori della famiglia x86 che fanno girare i computer di casa, porta con sé una serie di regali. Il primo regalo è che i registri del dispositivo diventano variabili come le altre, e questo permette di scrivere i driver in linguaggio C senza sfoderare il linguaggio assembler per ogni lettura. Il secondo è la protezione, perché basta al sistema operativo tenere quelle pagine di indirizzi fuori dallo spazio dell'utente, anzi, disponendo i registri di ogni dispositivo in pagine diverse, si può dare a un programma il permesso di usare una stampante e negargli il disco semplicemente aggiungendo o togliendo pagine dalla sua tabella. Il terzo regalo è che ogni istruzione che sa trattare la memoria sa anche trattare i registri, così un semplice ciclo di attesa può interrogare una porta con un'istruzione sola. Il prezzo si chiama cache, cioè la memoria veloce dove il processore tiene copie degli indirizzi usati di recente, perché se la porta finisse copiata nella cache il programma leggerebbe sempre la vecchia fotografia e resterebbe in attesa per l'eternità senza accorgersi che il dispositivo ha finito, e per questo l'hardware deve saper disattivare la cache pagina per pagina proprio dove vivono i registri.
Arriviamo ora al cuore del problema, e cioè al modo in cui la CPU trascorre il proprio tempo mentre il dispositivo lavora, e la soluzione più ingenua ha un nome onesto, l'ingresso e uscita programmata, anche detta interrogazione ciclica o polling, e consiste nel far fare alla CPU tutto il lavoro da sola. Immaginiamo di voler stampare una parola, e immaginiamo il sistema operativo che copia la parola nel proprio territorio, scrive il primo carattere nel registro dati della stampante e poi, per sapere quando la stampante è di nuovo pronta, entra in un anello strettissimo che legge il registro di stato ancora e ancora, centinaia di migliaia di volte al secondo, e non fa altro. Il paragone domestico è quello dell'ospite che, avviato il forno, scende dal terrazzo a controllare il pane ogni trenta secondi, e naturalmente non riesce a tenere una conversazione, a leggere un libro o a sparecchiare, perché le gambe lo portano giù di continuo a sbirciare attraverso il vetro.
L'interrogazione ciclica va bene soltanto in due casi limpidi, e cioè quando il dispositivo risponde in un lampo o quando la CPU, come nei piccoli controllori embedded, non ha comunque niente di meglio da fare, e in tutti gli altri casi spreca un tesoro. La via d'uscita è l'idea più fertile di tutta la storia dei calcolatori, l'interrupt, che in italiano chiamiamo interruzione e che il libro presenta come la campanella della porta d'ingresso. Invece di scendere a controllare il forno ogni trenta secondi, l'ospite mette il timer del forno e si siede tranquillo sul terrazzo, e quando il pane è pronto la campanella suona, l'ospite alza il sedere e scende a prenderselo. La campanella è il segnale elettrico che il dispositivo solleva su una linea del bus quando ha finito il compito assegnato, e nella pagina dedicata alla memoria, ai bus e all'ingresso e uscita avevamo già incontrato queste campanelle mentre seguivamo i fili della macchina, promettendo di raccontarne il mestiere più approfonditamente, e la promessa si scioglie adesso.
Vediamo per filo e per segno cosa accade quando suona la campanella. Ogni dispositivo è collegato a una linea di interruzione del bus, e sulla scheda madre siede un chip, il controllore delle interruzioni, che spia quelle linee e decide a chi dare retta quando arrivano più richieste insieme, secondo priorità scritte nell'hardware. Per servire la richiesta, il controllore piazza sulle linee di indirizzo del bus un numero che identifica il dispositivo, e quel numero funziona da indice in una tabella conservata in memoria, il vettore delle interruzioni, dentro cui sta l'indirizzo della procedura di servizio corrispondente. La CPU, interrotta nel bel mezzo di un altro lavoro, salva il proprio program counter e le proprie spie sullo stack, esattamente come avevamo imparato per le chiamate di procedura, salta alla procedura di servizio, e questa, appena cominciata, scrive nel controllore un valore di conferma che libera la linea per la prossima campanella. C'è poi un dettaglio moderno che vale la pena sfiorare, perché le CPU di oggi, pipeline e superscalari, portano avanti molte istruzioni insieme a gradi diversi di completamento, così quando suona la campanella alcune restano a metà, e un interrupt che lascia comunque la macchina in uno stato leggibile si dice preciso, una garanzia che costa spazio sul chip e complicazione nel progetto.
Anche con gli interrupt, però, resta uno spreco, perché per trasferire un blocco intero dal disco alla memoria il processore dovrebbe comunque ricevere una campanella a ogni parola e fare da facchino per migliaia di giri. La risposta si chiama accesso diretto alla memoria, DMA dalle parole inglesi, ed è un secondo assistente, un controllore che siede sul bus accanto alla CPU e sa parlare con la memoria senza chiedere il permesso. Il gioco si svolge in quattro mosse, e il libro le disegna una per una. Il processore scrive nei registri del controllore DMA l'indirizzo di memoria dove depositare i dati, il numero di byte da spostare e la direzione del viaggio, poi ordina al controllore del disco di leggere il blocco nel proprio buffer e di verificare il codice di correzione. A quel punto il controllore DMA chiede al bus la parola successiva e la scrive in memoria contando da sé, come un magazziniere che sposti casse dal camion allo scaffale con il proprio carrello, e quando il conteggio dei byte arriva a zero suona l'unica campanella di tutta l'operazione, avvisando il processore che il blocco è ormai a casa.
Il controllore DMA ha i suoi modi di lavorare, e conoscerli aiuta a decifrare le voci dei giornali tecnici. Nel modo a parola per parola chiede il bus una parola alla volta, e siccome ruba ogni tanto un ciclo di bus alla CPU si dice che pratichi il furto di ciclo, un ritardo appena percettibile che permette a entrambi di lavorare insieme. Nel modo a raffica invece prende il bus in prestito, sposta un blocco intero e poi lo restituisce, ed è più efficiente ma può lasciare la CPU in attesa per un tempo sensibile se la raffica è lunga. Nei computer veri esiste di solito un unico controllore DMA con diversi canali, uno per dispositivo, e sotto ogni scrivania i trasferimenti della scheda audio, del disco e della rete viaggiano proprio così. Resta infine una curiosità che chiarisce tutto, e cioè perché il disco legga prima tutto nel proprio buffer interno anziché mandare i bit direttamente in memoria appena arrivano, e la ragione è che il codice di correzione va verificato prima di sporcare la memoria con dati malati, e i bit escono dal disco a ritmo costante che non si ferma se il bus è occupato, così il buffer intermedio permette di trasferire con calma al momento giusto.
Abbiamo finora parlato di fili, bus e campanelle, ed è ora di salire di un piano, da dove si vedono i principi del software di ingresso e uscita, e il primo principio ha un nome che suona come un ideale, l'indipendenza dal dispositivo, e significa che un programma deve poter leggere un file dal disco rigido, da un disco ottico o da una chiavetta senza sapere in anticipo dove il file si trova e senza cambiare di una riga. Accanto all'indipendenza cammina la denominazione uniforme, e qui la pagina sul file system torna a farsi viva, perché è lei che insegna come, in un sistema ben nato, ogni dispositivo compaia nell'albero delle directory con un nome come un file qualunque, così che copiare un documento sulla chiavetta montata in una certa cartella sia identico, per il programma, a copiarlo in qualsiasi altra cartella del mondo.
Gli altri principi si dispongono in fila come articoli di uno statuto. La gestione degli errori deve avvenire il più vicino possibile all'hardware, perché il controllore che scopre un errore di lettura provi prima a correggerlo da solo, poi il driver riprovi a leggere il blocco, e solo se i piani bassi si arrendono la notizia salga verso l'utente, dato che molti errori, come un pulviscolo sulla testina, guariscono da soli al secondo tentativo. Le operazioni fisiche sono asincrone, guidate da interrupt, ma i programmi degli utenti sono più semplici se le operazioni appaiono bloccanti, e sta al sistema operativo conciliare i due mondi. Serve poi il buffering, cioè una zona di memoria dove far sostare i dati quando chi li produce e chi li consuma vanno a velocità diverse, e infine occorre distinguere i dispositivi condivisibili, come i dischi, da quelli dedicati, come le stampanti, che vanno assegnati a un utente per volta.
Con gli statuti appesi al muro, il libro costruisce l'edificio in quattro piani, e vale la pena impararne i nomi perché li ritroverai ovunque. In basso, appena sopra l'hardware, stanno le procedure di gestione delle interruzioni, i camerieri che rispondono alle campanelle. Sopra di loro lavorano i driver dei dispositivi, il piano più vicino ai dialetti elettrici di ciascuna macchina. Al terzo piano troviamo il software di ingresso e uscita indipendente dal dispositivo, che offre a tutti i piani superiori un volto unico e gentile, e in cima, nello spazio dell'utente, vivono le librerie e i programmi che chiudono il cerchio. Li visiteremo salendo uno alla volta, con la disciplina di chi sa che ogni piano comunica soltanto con quello immediatamente sopra e sotto, e che questa regola di confini è ciò che rende possibile aggiungere dispositivi nuovi senza riscrivere il mondo.
Le procedure di interruzione hanno un compito umile e preciso, e cioè nascondere le campanelle. Il trucco sta nel fatto che quando un driver avvia un'operazione si blocca volontariamente, e quando l'interrupt arriva la procedura di servizio fa il suo lavoro minimo e poi lo sveglia, così che per il resto del sistema un'operazione guidata da interrupt appaia come una semplice attesa con un lieto fine. Saliamo al piano dei driver, e qui troviamo la figura che dà il titolo a tutta la pagina. Ogni dispositivo ha bisogno di un programma suo, scritto di solito dal costruttore e consegnato insieme all'apparecchio, perché il numero e il significato dei registri variano in modo radicale da macchina a macchina, e chi scrive il driver del mouse deve capire i movimenti e i pulsanti, mentre chi scrive il driver del disco deve conoscere settori, piste, cilindri e i tempi di assestamento della testina.
Il driver è, nell'immagine che regaliamo alla memoria, l'interprete in una trattativa di affari fra due delegazioni che parlano lingue diverse. Da un lato della tavola siede il sistema operativo, che conosce soltanto frasi astratte come leggi il blocco numero cinquanta o scrivi questa riga, e dall'altro lato siede il controllore, che capisce soltanto ordini concreti e minuziosi come muovi il braccio sul cilindro venti, aspetta che il settimo settore passi sotto la testina e accendi il motore, e l'interprete traduce la prima frase nella seconda, parola per parola, tenendo il tono giusto. Proprio perché deve scrivere nei registri del controllore, il driver vive di solito dentro il kernel, in territorio protetto, e qui conviene registrare un'eccezione che fa da ponte alla prossima pagina, perché esiste un sistema, MINIX, dove i driver vivono invece come processi normali nello spazio dell'utente, isolati e rinnovabili, e la pagina successiva spiegherà perché questa scelta cambia la vita di chi costruisce sistemi.
Guardiamo il driver all'opera in una giornata tipo, e scopriamo una coreografia sempre uguale. Il driver riceve una richiesta astratta e prima controlla che i parametri siano sensati, poi traduce il numero di blocco logico nei numeri di testina, pista e settore che il disco capisce, accoda la richiesta se il dispositivo è occupato, verifica lo stato dell'hardware, spedisce al controllore la sequenza dei comandi registro dopo registro, e infine si blocca in attesa dell'interrupt se l'operazione richiede tempo, oppure conclude in un lampo se era facile, come lo scorrimento del testo sullo schermo. Sopra di lui, il piano indipendente dal dispositivo dà a tutti i driver la stessa interfaccia, una tabella di puntatori alle funzioni che il sistema impara all'atto del caricamento, così che un driver nuovo si inserisca come una spina nella presa giusta, e stabilisce persino una dimensione di blocco uniforme, nascondendo il fatto che settori fisici diversi possono avere misure diverse.
Sempre in questo piano accadono cose che si toccano ogni giorno senza saperlo. È qui che il nome simbolico di un dispositivo viene tradotto nel driver giusto, perché in un sistema come Linux il nome della periferica individua un file speciale dentro cui stanno due numeri, il numero maggiore che sceglie il driver e il numero minore che indica quale unità fra le gemelle si intende, ed è qui che valgono i permessi dei file, così che l'amministratore possa decidere chi ha diritto di parlare con la stampante. È qui che avviene il buffering vero, con i doppi buffer che si alternano come due secchi al pozzo, e qui che nasce lo spooling, la coda di stampa in cui un processo speciale, il daemon, è l'unico autorizzato a tenere aperto il file della stampante, mentre tutti gli altri programmi depositano i documenti in una cartella d'attesa da cui il demone li preleva uno alla volta, un'idea che tiene in piedi gli uffici di mezzo mondo.
Con le scale in tasca, affrontiamo il primo macchinario vero, il disco, e cominciamo dal tipo magnetico, il disco rigido che quasi certamente ospita i file della vita digitale di casa. Dentro l'involucro troviamo una pila di piatti circolari d'alluminio o di vetro, tipicamente larghi tre pollici e mezzo, ricoperti di un ossido metallico che si lascia magnetizzare come la calamita delle elementari, e sopra ogni superficie vola una testina sottilissima che non tocca mai il piatto, perché il contatto distruggerebbe entrambi. Le testine sono saldate a un unico braccio che le muove tutte insieme, come le dita di una mano che sfogliano dieci quaderni appoggiati uno sull'altro, e a ogni posizione del braccio corrisponde un cilindro, cioè l'insieme delle piste che stanno simultaneamente sotto le testine, con ogni pista divisa in settori che di solito custodiscono cinquecentododici byte l'uno.
Tre quantità decidono quanto dura la lettura di un blocco, e il libro le elenca con la calma di un perito. C'è il tempo di seek, cioè il tempo che il braccio impiega a portarsi sul cilindro giusto, ed è di gran lunga il più costoso, perché muovere metallo ha inerzia e richiede millisecondi. C'è il ritardo rotazionale, cioè l'attesa che il settore desiderato compia il giro e passi sotto la testina, e in media vale mezza rotazione. C'è infine il trasferimento vero e proprio, che è fulmineo, e la morale è che muovere il braccio costa più di tutto il resto messo insieme, ragion per cui gli ingegneri spremono ogni trucco per muoverlo il meno possibile. I dischi moderni complicano poi la geometria con le zone, perché le piste esterne, più lunghe, ospitano più settori di quelle interne, e presentano al sistema operativo una geometria virtuale semplificata mentre il controllore custodisce la mappa vera, fino al punto che oggi i settori vengono chiamati semplicemente per numero progressivo, con l'indirizzamento a blocchi logici.
Un disco nuovo di fabbrica non sa nulla di sé, e prima di servire deve ricevere la formattazione di basso livello, un'operazione che scrive sulle piste la struttura dei settori, e ogni settore portafoglio si compone di un preambolo che dice dove si trova, dei dati veri e propri e del codice di correzione che permette di riparare piccoli danni di lettura, con qualche settore di riserva nascosto ogni tanto. Siccome nessuna fabbrica riesce a produrre superfici perfette, i dischi nascono con settori malati, e il controllore li scambia con i settori di riserva tenendo una lista dei sostituti, un po' come il portiere di uno stabile che, trovata una buca nel muro dell'androne, sposti la cassetta delle lettere nella nicchia accanto e segni il cambio sul proprio quaderno, così che il postino continui a consegnare senza accorgersi di nulla.
Proprio perché spostare il braccio costa caro, il driver smista le richieste in attesa con le astuzie di un ascensorista di un grattacielo. La strategia ingenua serve le richieste nell'ordine di arrivo, e se il piano chiamato è il tre, poi il trentadue, poi il due, la cabina corre su e giù come una trottola. Servire sempre prima la richiesta più vicina risparmia chilometri ma condanna i piani estremi a un'attesa lunga quando il traffico è fitto, perché l'ascensore resta a girare intorno ai piani medi. La mossa geniale, che nel libro si chiama algoritmo dell'ascensore e che i dischi usano davvero, è proseguire sempre nella stessa direzione finché ci sono chiamate da quella parte e poi invertire il senso, con un solo bit di memoria, e qui si scioglie il cuore della pagina sul file system, e cioè perché il sistema cerchi con tanta cura di tenere vicini fra loro i blocchi dello stesso file, perché vicini al braccio significano pochi spostamenti, e pochi spostamenti significano un computer scattante.
Accanto al disco magnetico siede, da qualche decennio a questa parte, il disco allo stato solido, che in inglese chiamiamo SSD, e conviene conoscerlo perché il computer di casa forse ne possiede uno. Non ha piatti, braccia né motori, perché custodisce i dati in banche di memoria flash, cioè in griglie di celle elettroniche che trattengono la carica come piccolissime bottiglie, e la lettura è istantanea e silenziosa. Ogni cella però sopporta soltanto un numero limitato di cicli di scrittura e cancellazione, dopo di che si stanca come una gomma che perde il disegno, e per questo i controllori degli SSD praticano il livellamento dell'usura, spostando di continuo i dati freschi sulle celle più riposate affinché tutto il dispositivo invecchi allo stesso ritmo, un po' come un capo reparto giusto che alterna i turni fra gli operai per non stancarne nessuno. Al sistema operativo l'SSD si presenta con lo stesso vocabolario a blocchi del fratello magnetico, e questo è il trionfo dell'indipendenza dal dispositivo raccontata poco fa.
Lasciamo i dischi e salutiamo un personaggio silenzioso che lavora anche quando lo schermo dorme, l'orologio, che il libro chiama anche timer e che non è né a blocchi né a caratteri, perché il suo unico prodotto è la campanella suonata a intervalli regolari. L'hardware dell'orologio programmabile si compone di tre pezzi, un quarzo tagliato sotto tensione che batte con precisione da sveglia svizzera a centinaia di milioni di pulsazioni al secondo, un contatore che scala quei battiti e si scarica fino a zero, e un registro di carico che decide da quale numero cominciare il conto alla rovescia. Quando il contatore tocca zero, suona l'interrupt, e se il registro ricarica il contatore da solo i colpi diventano periodici e prendono il nome di tick, i battiti d'orologio del sistema, da sessanta a mille al secondo secondo le epoche e le scuole. E siccome un computer spento deve pur sapere che ora è quando si risveglia, sulla scheda madre vive un secondo orologio alimentato a batteria, quello da polso, che il sistema consulta all'accensione.
Tutto il resto del lavoro dell'orologio è software, ed è una giornata piena che riempie la vita di un metronomo. Il primo dovere è tenere l'ora del giorno, e qui il libro racconta un trucco elegante, perché contare i battiti dall'inizio dei tempi in trentadue bit farebbe traboccare il contatore in un paio d'anni, e allora si conta in secondi con un secondo contatore per i battiti rimasti, oppure si conta rispetto all'accensione della macchina e si somma l'ora letta dall'orologio a batteria. Il secondo dovere è impedire a un processo di monopolizzare la CPU, e qui l'orologio stringe la mano alla pagina sui processi, perché a ogni battito il driver scala il quanto di tempo assegnato al processo corrente e, quando il conto tocca lo zero, chiama lo schedulatore per dare il turno a un altro. Poi vengono la contabilità del tempo di CPU, le sveglie richieste dai programmi con la loro lista ordinata di scadenze, i timer da guardiano che riavviano le apparecchiature impazzite, e la profilazione che misura dove i programmi spendono le proprie giornate.
È tempo di chiudere il cerchio con l'esempio che il libro ama di più, il terminale, perché la storia di come una lettera premuta sulla tastiera finisca dipinta sullo schermo riassume tutti i livelli che abbiamo visitato. Ai tempi dei grandi calcolatori multitutente ogni utente remoto aveva un apparecchio che univa una tastiera e un piccolo schermo, chiamato terminale, e la parola è sopravvissuta alle macchine, visto che oggi chiamiamo terminale la finestra scura dove programmatori e curiosi digitano i comandi. La tastiera contiene un microprocessore tutto suo e genera un interrupt a ogni tasto premuto e un secondo interrupt a ogni tasto rilasciato, e nel registro dell'interfaccia arriva un numero che è il codice di scansione del tasto, non ancora una lettera, perché spetta al driver ricordare quali tasti sono giù e decidere se quel trentesimo codice, con lo spostamento premuto, voglia dire una A maiuscola, un control oppure qualche altra combinazione.
Da qui in poi il driver sceglie fra due filosofie, e la scelta ha nomi che ritroverai nelle pagine di manuale. Nella modalità grezza, raw mode, i programmi ricevono i caratteri così come arrivano, con tutti gli sbagli di battitura inclusi, ed è la modalità amata dagli editor sofisticati. Nella modalità cotta, cooked mode, che lo standard chiama canonica, il driver raccoglie i caratteri riga per riga, onora i tasti speciali che cancellano l'ultima lettera o la riga intera, converte il tasto invio nel carattere giusto per il sistema, e consegna al programma solo la riga rifinita, dopo averla fatta comparire sullo schermo con l'eco, tenendo da parte i caratteri battuti in anticipo mentre il programma era occupato. Quando poi il programma risponde, il suo testo scende verso il buffer di memoria dello schermo, mappato nello spazio di indirizzi come hai imparato, e lì i livelli si stringono la mano, dal bit sul bus al glifo luminoso.
Il senso d'insieme, ora che la visita è completa, sta in una frase sola, e cioè che l'ingresso e l'uscita è il posto dove la macchina smette di essere un gioiello chiuso in una vetrina e diventa casa, officina e piazza. Ogni piano che abbiamo attraversato, dalle porte di memoria ai driver interprete, dall'accesso diretto all'orologio che assegna i turni, esiste per una ragione tenera, e cioè permettere a chi ha imparato a leggere l'albero dei file e a riconoscere i registri del processore di usare il computer come uno strumento al proprio servizio anziché come una scatola misteriosa. E c'è una promessa che il percorso di Tutanum ha già scritto sulla porta della stanza successiva, e cioè che chi capisce come i driver traducono i desideri in comandi elettrici, prima o poi si costruisce un sistema operativo tutto suo, con le proprie mani, riga dopo riga, e nella prossima pagina cominceremo a parlare proprio di come si mette in piedi un kernel vero.
La teoria di questa pagina, per quanto raccontata con calma, prende vita soltanto quando la
tocchi, quindi adesso lascia la poltrona della spiegazione e vieni al banco di prova con il
tuo computer, in cinque esperimenti tutti sicuri, nessuno dei quali chiede di smontare nulla
né di aprire il case. Per il primo apri il terminale e digita cat /proc/interrupts,
che ti mostra il registro pubblico delle campanelle del tuo computer, con il conteggio di
quante volte ciascun dispositivo ha interrotto il processore, e osserva le righe dedicate alla
tastiera e al disco. Ora muovi il mouse per qualche secondo e ridai lo stesso comando, e
vedrai il contatore del mouse cresciuto sotto i tuoi occhi, il che significa che avrai appena
seguito da spettatore centinaia di interrupt gestiti dal controllore delle interruzioni mentre
leggevi questa frase.
Per il secondo esperimento chiedi al sistema di presentarti i suoi dispositivi a blocchi con
lsblk, oppure leggi la lista delle partizioni con cat /proc/partitions,
e vedrai i dischi chiamati con nomi come sda e le loro partizioni disposte in
ordine, i nodi stessi che la pagina sul file system ti ha insegnato a montare nelle directory.
Poi, per ascoltare il piano dei driver che si annunciano al sistema, digita dmesg
e cerca fra le righe i messaggi in cui il kernel racconta di aver trovato un disco, di averne
letta la geometria e di aver caricato il driver giusto, oppure usa lspci e
lsusb per elencare i controllori presenti sul bus e le periferiche attaccate alla
porta universale, così vedrai con che regolarità le due famiglie di dispositivi si presentino
al mondo.
Per il terzo esperimento mettiti alla prova con la campanella dell'orologio, perché digitando
date +%s il terminale ti risponde con un numero enorme che sono i secondi trascorsi
dalla mezzanotte del primo gennaio del millenovecentosettanta, il momento zero da cui il tuo
sistema conta il tempo, esattamente il trucco dei contatori che hai letto poche colonne fa. Con
uptime vedi invece da quanto il computer è acceso e quanti utenti lo abitano, e se
vuoi assistere al lavorio continuo dell'orologio digita watch -n 1 cat /proc/uptime
e osserva il primo dei due numeri crescere di un'unità ogni secondo, battere su battere, come
un metronomo che non si stanca mai.
Per il quarto esperimento gioca con il terminale stesso, che è la tua finestra su tutti i
livelli, e digita stty -a per leggere le impostazioni correnti della tastiera,
dove troverai scritto quali tasti cancellano la riga, quali bloccano lo scorrimento e quale
segnala la fine del file. Prova a premere insieme il tasto di controllo e la lettera s, e
osserva come l'uscita del terminale si blocchi all'istante, poi premi il tasto di controllo con
la lettera q per liberarla, esattamente i tasti speciali del buffer di ingresso canonico di cui
hai letto la teoria, e se ti senti audace digita stty erase ^h per cambiare il
tasto di cancellazione e poi stty erase ^? per tornare indietro, così avrai dato
una pacca al driver che interpreta le tue dita.
Per il quinto ed ultimo esperimento chiedi notizie del disco con sudo hdparm -I /dev/sda
se possiedi un disco magnetico, oppure sudo smartctl -a /dev/nvme0n1 se il tuo
computer ha un disco allo stato solido, e fra i dati che ricevi cerca i settori, le geometrie
e, nei modelli recenti, le ore di accensione e i cicli di scrittura consumati, i segni del
tempo che ogni disco porta con sé come le rughe sul volto. Infine, per sentire il ritmo del
braccio, copia un file grande dentro la cartella temporanea con dd if=/dev/zero of=/tmp/prova bs=1M count=512
e cronometra il tempo impiegato, poi cancella il file e ripeti l'operazione dopo aver aperto
qualche programma pesante, così capirai sul pavimento di casa la differenza fra blocchi vicini
e blocchi lontani.
Il modulo attinge soprattutto al capitolo sull'ingresso e l'uscita del libro Modern Operating Systems di Andrew S. Tanenbaum, dove i principi dell'hardware di ingresso e uscita, le porte e la memoria mappata, gli interrupt e l'accesso diretto alla memoria, i livelli del software con i driver, i dischi e i loro algoritmi di scheduling, gli orologi e le loro scadenze e infine il terminale con le sue modalità di ingresso ricevono trattazione piena, con le figure dei bus e le tabelle dei tempi a fare da bussola.
Hai percorso con calma tutta la strada che va dal bit sul bus al file nell'albero, e ora sai esattamente cosa fa il sistema ogni volta che premi un tasto e ogni volta che il disco gira per soddisfare una tua richiesta. Se questo traffico fra elettroni e meccanica ti ha stregato, la stanza successiva ti aspetta con il cantiere aperto, perché la prossima pagina smonta e rimonta il cuore stesso del sistema operativo su un palcoscenico vero e piccolo, il kernel e il maestoso MINIX, e ti invitiamo a proseguire verso la pagina successiva per mettere le mani in pasta per davvero.