Gestione strutturata del sistema operativo Modulo 3 – EiPass Progressive Sistema operativo In informatica il sistema operativo, abbreviato in SO (in inglese OS, "operating system") è un particolare software, installato su un sistema di elaborazione, che ne garantisce l'operatività di base coordinando le risorse hardware di processamento, memorizzazione e le periferiche e senza il quale quindi non sarebbe possibile l'utilizzo di altri software più specifici, come applicazioni o librerie software, e quindi in ultimo del computer stesso. Esso funge quindi da "base" al quale si appoggiano gli altri software, che dunque dovranno essere progettati in modo da essere riconosciuti e supportati da quel particolare sistema operativo. Per sistema operativo intendiamo quindi l'insieme dei componenti software che hanno il duplice scopo di gestire le risorse hardware e software del computer, e fare da interfaccia tra l'utente e l'hardware. Assieme al processore, con cui è strettamente legato, costituisce la cosiddetta piattaforma del sistema di elaborazione. Funzioni principali Secondo una definizione più rigorosa, il sistema operativo è un insieme di subroutine e strutture dati responsabili: del controllo e della gestione delle componenti hardware che costituiscono il computer (processi di input/output da e verso le periferiche collegate al sistema) dell'esecuzione dei programmi (processi) che su di esso vengono eseguiti. [1]. Se il sistema di elaborazione prevede la possibilità di memorizzazione aggiuntiva dei dati su memoria di massa, come accade nei computer general purpose, esso ha anche il compito di: gestire l'archiviazione e l'accesso ai file. I programmi possono gestire l'archiviazione dei dati su memoria di massa (ottenendo strutture complesse, come un database), servendosi delle procedure messe a disposizione del sistema operativo. La componente del SO che si occupa di tutto ciò viene chiamata file system. Infine, se è prevista interazione con l'utente, viene solitamente utilizzata allo scopo un'interfaccia software (grafica o testuale) per accedere alle risorse hardware (dischi, memoria, I/O in generale) del sistema. D'altra parte, un sistema operativo può essere utilizzato anche su una macchina che non preveda interazione diretta con un essere umano (per un esempio, vedi smart card o determinati sistemi embedded) spesso dunque più leggero e semplificato. Solitamente un sistema operativo installato su computer fornisce anche degli applicativi di base per svolgere elaborazioni di diverso tipo. Sebbene molte delle funzionalità sopraddette non siano spesso immediatamente visibili/percepibili dall'utente, l'importanza del sistema operativo di un calcolatore è cruciale: oltre alla necessità di gestione delle funzionalità di base sopraddette, al di là delle prestazioni massime offerte dall'hardware 1 dell'elaboratore stesso, il sistema operativo determina di fatto efficienza e buona parte delle prestazioni effettive di funzionamento dell'intero sistema ad esempio in termini di latenze di processamento, stabilità, interruzioni o crash di sistema. Struttura Un generico sistema operativo moderno si compone di alcune parti standard, più o meno ben definite. Il kernel un gruppo di funzioni fondamentali, strettamente interconnesse fra loro e con l'hardware, che vengono eseguite con il privilegio massimo disponibile sulla macchina ossia in modalità kernel; il kernel fornisce le funzionalità di base per tutte le altre componenti del sistema operativo, che assolvono le loro funzioni servendosi dei servizi che esso offre. Il gestore di file system si occupa di esaudire le richieste di accesso alle memorie di massa. Viene utilizzato ogni volta che si accede a un file sul disco, e oltre a fornire i dati richiesti tiene traccia dei file aperti, dei permessi di accesso ai file. Inoltre si occupa anche e soprattutto dell'astrazione logica dei dati memorizzati sul computer (directory, ecc). Un sistema di memoria virtuale che alloca la memoria richiesta dai programmi e dal sistema operativo stesso, salva sulla memoria di massa le zone di memoria temporaneamente non usate dai programmi e garantisce che le pagine swappate vengano riportate in memoria se richieste. Uno scheduler che scandisce il tempo di esecuzione dei vari processi e assicura che ciascuno di essi venga eseguito per il tempo richiesto. Normalmente lo scheduler gestisce anche lo stato dei processi e può sospenderne l'esecuzione nel caso questi siano in attesa senza fare nulla (esempio classico è la richiesta di dati da disco). Nei sistemi operativi realtime lo scheduler si occupa anche di garantire una timeline, cioè un tempo massimo di completamento per ciascun task in esecuzione, ed è notevolmente più complesso. Uno spooler che riceve dai programmi i dati da stampare e li stampa in successione, permettendo ai programmi di proseguire senza dover attendere la fine del processo di stampa. Una interfaccia utente (Shell) che permette agli utenti di interagire con la macchina. A seconda dei casi, un particolare sistema operativo può avere tutti questi componenti o solo alcuni. DOS (Disk Operating Systems) Un computer diventa molto più utile ed efficace se dotato di una memoria di massa: per gestirla serve un gestore di file system, cioè un software che in sintesi è composto da un insieme di funzioni che permetta di organizzare e gestire (accesso o lettura, scrittura o memorizzazione, ordinamento) i dati sulla superficie dei mezzi di memorizzazione secondo una struttura ben precisa. I sistemi operativi che risiedevano su disco e capaci di gestire un file system sono detti genericamente Disk Operating System, cioè DOS appunto. L'esemplare più famoso è senz'altro l'MS-DOS di Microsoft, oggi non più in uso, ma che era alla base dei 2 sistemi operativi Windows 95/98/Me. Ne esiste anche una versione libera compatibile con i suoi programmi, il FreeDOS, ed altre versioni come il DR-DOS. Processi Programmi e processi Un programma è costituito dal codice oggetto generato dalla compilazione del codice sorgente, ed è normalmente salvato sotto forma di uno o più file. Esso è un'entità statica, che rimane immutata durante l'esecuzione. Il processo è l'entità utilizzata dal sistema operativo per rappresentare una specifica esecuzione di un programma. Esso è quindi un'entità dinamica, che dipende dai dati che vengono elaborati, e dalle operazioni eseguite su di essi. Il processo è quindi caratterizzato, oltre che dal codice eseguibile, dall'insieme di tutte le informazioni che ne definiscono lo stato, come il contenuto della memoria indirizzata, i thread, i descrittori dei file e delle periferiche in uso. Processi e thread Il concetto di processo è associato, ma comunque distinto da quello di thread (abbreviazione di thread of execution, filo dell'esecuzione) con cui si intende invece l'unità granulare in cui un processo può essere suddiviso (sottoprocesso) e che può essere eseguito a divisione di tempo o in parallelo ad altri thread da parte del processore. In altre parole, un thread è una parte del processo che viene eseguita in maniera concorrente ed indipendente internamente allo stato generale del processo stesso. Il termine inglese rende bene l'idea, in quanto si rifà visivamente al concetto di fune composta da vari fili attorcigliati: se la fune è il processo in esecuzione, allora i singoli fili che la compongono sono i thread. Un processo ha sempre almeno un thread (se stesso), ma in alcuni casi un processo può avere più thread che vengono eseguiti in parallelo. Una differenza sostanziale fra thread e processi consiste nel modo con cui essi condividono le risorse: mentre i processi sono di solito fra loro indipendenti, utilizzando diverse aree di memoria ed interagendo soltanto mediante appositi meccanismi di comunicazione messi a disposizione dal sistema, al contrario i thread di un processo tipicamente condividono le medesime informazioni di stato, la memoria ed altre risorse di sistema. L'altra differenza sostanziale è insita nel meccanismo di attivazione: la creazione di un nuovo processo è sempre onerosa per il sistema, in quanto devono essere allocate ovvero assegnate risorse necessarie alla sua esecuzione (allocazione di memoria, riferimenti alle periferiche, e così via, operazioni tipicamente onerose); il thread invece è parte di un processo e quindi una sua nuova attivazione viene effettuata in tempi ridottissimi a costi minimi. Le definizioni sono le seguenti: Il processo è l'oggetto del sistema operativo a cui sono assegnate tutte le risorse di sistema per l'esecuzione di un programma, tranne la CPU. Il thread è l'oggetto del sistema operativo o dell'applicazione a cui è assegnata la CPU per l'esecuzione. 3 In un sistema che non supporta i thread, se si vuole eseguire contemporaneamente più volte lo stesso programma, è necessario creare più processi basati sullo stesso programma. Tale tecnica funziona, ma è dispendiosa di risorse, sia perché ogni processo deve allocare le proprie risorse, sia perché per comunicare tra i vari processi è necessario eseguire delle relativamente lente chiamate di sistema, sia perché la commutazione di contesto tra thread dello stesso processo è più veloce che tra thread di processi distinti. Avendo più thread nello stesso processo, si può ottenere lo stesso risultato allocando una sola volta le risorse necessarie, e scambiando i dati tra i thread tramite la memoria del processo, che è accessibile a tutti i suoi thread. Un esempio di applicazione che può far uso di più thread è un browser Web, che usa un thread distinto per scaricare ogni immagine in una pagina Web che contiene più immagini. Un altro esempio è costituito dai processi server, spesso chiamati servizi o daemon, che possono rispondere contemporaneamente alle richieste provenienti da più utenti. In un sistema multiprocessore (SMP), si possono avere miglioramenti prestazionali, grazie al parallelismo fisico dei thread. Tuttavia, l'applicazione deve essere progettata in modo tale che essa suddivida tra i thread il carico di elaborazione. Tale progettazione è difficile e soggetta a errori, e il programma risultante, se eseguito su un sistema monoprocessore, potrebbe essere più lento di uno con un solo thread; pertanto oggi sono ancora pochi i software che usano i thread per sfruttare i sistemi SMP. Supporto del sistema operativo I sistemi operativi si classificano nel seguente modo in base al supporto che offrono a processi e thread: Monotasking: non sono supportati né processi né thread; si può lanciare un solo programma per volta. Multitasking cooperativo: sono supportati i processi, ma non i thread, e ogni processo mantiene la CPU finché non la rilascia spontaneamente. Multitasking preventivo: sono supportati i processi, ma non i thread, e ogni processo mantiene la CPU finché non la rilascia spontaneamente o finché il sistema operativo sospende il processo per passare la CPU a un altro processo. Multithreaded: sono supportati sia i processi, sia i thread. Multitasking embedded: sono supportati i thread, ma non processi, nel senso che si può eseguire un solo programma per volta, ma questo programma può avere più thread (solitamente detti task). Sistema multi task I programmi non hanno sempre realmente bisogno della CPU: a volte, invece di eseguire istruzioni, stanno aspettando che arrivino dei dati da un file, o che l'utente prema un tasto della tastiera. Quindi si può, in linea di principio, usare questi tempi "morti" per far eseguire un altro programma. Questa idea, sorta fin dai primi anni cinquanta, si concretizzò nei sistemi operativi multitasking, cioè dotati di uno scheduler che manda in esecuzione più processi (esecuzioni di programmi), assegnando a turno la CPU a ognuno e sospendendo l'esecuzione dei programmi in attesa di un evento esterno (lettura/scrittura sulle memorie di massa, stampa, input utente ecc.) finché questo non si verifica. 4 Dovendo ospitare in memoria centrale più programmi nello stesso tempo, i sistemi multitask hanno bisogno di più memoria rispetto a quelli monotask: perciò questo tipo di sistemi operativi è quasi sempre dotato di un gestore di memoria virtuale. Inoltre, con più programmi simultaneamente attivi, il controllo delle risorse hardware diventa una reale necessità e non è più possibile farne a meno. Esistono sostanzialmente due modi di implementare il multitasking: cooperative e preemptive multitasking. Nel primo sono i programmi che, spontaneamente, cedono il controllo al sistema non appena hanno terminato la singola operazione in corso; nel secondo è lo scheduler che ferma i programmi allo scadere del tempo assegnato e trasferisce il controllo dall'uno all'altro. Il cooperative multitasking assorbe meno risorse di calcolo e non ha (quasi) ritardo di commutazione per il cambio di task, e inoltre non richiede nessuna struttura hardware dedicata, il che rende possibile implementarlo su qualunque calcolatore; per contro è molto vulnerabile a errori nei programmi (in genere il crash di un programma fa cadere l'intero sistema) e l'isolamento fra processi è molto debole. È il modello utilizzato da Mac OS 9, Windows 3.0 e precedenti. Il preemptive multitasking necessita di CPU che implementino in hardware sia dei livelli di privilegio per l'esecuzione del codice, sia una logica specifica per il context switch, il cambio di task eseguito dallo scheduler. Poiché l'interruzione dei programmi è arbitraria, al cambio di task il sistema operativo è costretto a salvare tutti o quasi i registri della CPU e ricaricarli con quelli salvati dal task che subentra, perdendo molto tempo. A fronte di queste maggiori richieste, il preemptive multitasking offre una sicurezza del sistema molto maggiore e una (virtuale) immunità ai crash di sistema causati da errori nei programmi. È il modello utilizzato dai moderni sistemi operativi. Stati di un processo In un sistema operativo multitasking, ci sono più processi contemporaneamente in esecuzione. Di questi, al massimo un numero pari al numero di processori può avere effettivamente il controllo di un processore in un dato istante. I diversi processi possono quindi utilizzare il processore per un periodo limitato di tempo cioè a divisione di tempo, per questo motivo i processi vengono interrotti, messi in pausa e richiamati secondo i noti algoritmi di schedulazione, dando l'impressione all'utente di un processamento parallelo di questi. Gli stati in cui un processo si può trovare sono: esecuzione (running): il processo ha il controllo di un processore; pronto (ready): il processo è pronto ad essere eseguito, ed è in attesa che lo scheduler lo metta in esecuzione; in attesa o sospeso o bloccato (suspended o blocked): il processo ha eseguito una chiamata di sistema ed è fermo in attesa del risultato; Con commutazione di contesto (Context switch) si indica il meccanismo tramite il quale un processo in esecuzione viene fermato (perché ha eseguito una chiamata di sistema o perché lo scheduler ha deciso di eseguire un altro processo), e un altro pronto viene messo in esecuzione. Algoritmo Schedulazione: First Come First Served L'algoritmo FCFS (First Come First Served) è un tipo di algoritmo FIFO: esegue i processi nello stesso ordine in cui essi vengono sottomessi al sistema. Il primo processo ad essere eseguito è esattamente quello che per primo richiede l'uso della CPU. Quelli successivi vengono serviti non appena questo ha terminato la 5 propria esecuzione, e così avviene successivamente per tutti gli altri posti in coda. Questo tipo di algoritmo è molto semplice da implementare ma solitamente è anche poco efficiente, almeno considerando il tempo medio d'attesa. Algoritmo Schedulazione: Round Robin L'algoritmo di scheduling RR (Round Robin) è un particolare algoritmo di tipo preemptive che esegue i processi nell'ordine d'arrivo, come il FCFS, ma esegue la prelazione del processo in esecuzione, ponendolo alla fine della coda dei processi in attesa, qualora l'esecuzione duri più del quanto di tempo stabilito, e facendo proseguire l'esecuzione al successivo processo in attesa. Ad esempio nell'ipotesi che vi siano i seguenti processi in coda con relativa durata in millisecondi, e quanto di tempo stabilito di 20 ms: p1 30 → p2 15 → p3 60 → p4 45 Verranno eseguiti nel seguente ordine: p1 (interrotto dopo 20 ms, ne rimangono altri 10) → p2 (termina la propria esecuzione perché dura meno di 20 ms) → p3 (interrotto dopo 20 ms, ne rimangono altri 40) → p4 (interrotto dopo 20 ms, ne rimangono altri 25) → p1 (termina la propria esecuzione perché necessitava di meno di 20 ms) → p3 (interrotto dopo 20 ms, ne rimangono altri 20) → p4 (interrotto dopo 20 ms, ne rimangono altri 5) → p3 (termina la propria esecuzione perché necessitava di esattamente 20 ms) → p4 (termina la propria esecuzione) Le prestazioni di quest'algoritmo sono dunque influenzate dal tempo medio d'attesa sebbene consenta a tutti i processi di ottenere il controllo della CPU ed evita quindi il problema dell'attesa indefinita (starvation). È inoltre da tenere in considerazione l'impatto dovuto ai frequenti context switch effettuati. È necessario quindi calcolare correttamente la durata ottimale del quanto di tempo per far sì che l'incidenza dei cambi di contesto sia abbastanza limitata come anche i tempi di attesa. Algoritmo Schedulazione: Shortest Job first Gli algoritmi SJF (Shortest job first) , non potendo conoscere il tempo per il quale il job occuperà il processore (per il Teorema della fermata), il sistema operativo utilizzerà i dati di precedenti elaborazioni. Sistema multiutente Se un computer può far girare più programmi contemporaneamente, allora può anche accettare comandi da più utenti contemporaneamente: in effetti dal multitasking alla multiutenza o timesharing il passo è tecnicamente molto breve, ma fa sorgere una serie di nuovi problemi dal punto di vista della sicurezza dei sistemi operativi: come distinguere i vari utenti tra loro, come accertarsi che nessun utente possa causare danni agli altri o alla macchina che sta usando. Questi problemi di sicurezza informatica si risolvono assegnando un account univoco per ciascun utente, assegnando un proprietario ai file ed ai programmi e gestendo un sistema di permessi per l'accesso ad essi, e prevedendo una gerarchia di utenti (cioè di account) per cui il sistema rifiuterà tutti i comandi potenzialmente "pericolosi" e li accetterà soltanto se impartiti da un utente in cima alla gerarchia, che è l'amministratore del sistema (generalmente l'account root nei sistemi Unix, Administrator nei sistemi Windows). 6 Sistema operativo on-line Mediante opportuni software, il sistema operativo può avere la funzionalità di desktop remoto, che consente tramite una connessione internet l'accesso al proprio elaboratore e a tutti gli applicativi e dati salvati in uno specifico momento. Tramite accesso remoto sono possibili le stesse operazioni che si possono fare stando davanti al proprio elaboratore. L'accesso è protetto da user e password che possono essere al limite condivisi da una comunità di utenti. In questo caso, il desktop remoto è un'evoluzione della tradizionale cartella condivisa. La cartella condivisa già permetteva la comunicazione di qualsiasi file, dunque anche di eseguibili, installabili da remoto in locale, oltreché di dati. Storia L'arrivo del personal computer (anni ottanta) Verso gli anni ottanta, grazie alla tecnologia LSI (large scale integration) la costruzione di chip integrati divenne massiccia e portò all'abbattimento dei prezzi dell'hardware, facendo sorgere l'era dell'elaboratore personale o personal computer. Queste macchine erano piccole, economiche ed avevano prestazioni simili a quelle dei calcolatori medio-grandi di 10-20 anni prima. I primi modelli erano dotati di sistemi operativi monoutente con accesso interattivo e supporto al time-sharing. Il più importante tra i primi sistemi operativi per personal computer era il CP/M-80 della Digital Research per le CPU 8080, 8085 e Z-80. Era basato sui sistemi operativi della Digital Equipment Corporation specialmente quelli per l'architettura PDP1. MS-DOS (o PC DOS quando fornito da IBM) era originariamente basato proprio sul CP/M-80. Microsoft contro Apple Steve Jobs era uno dei pochi che credeva nell'idea del personal computer. All'epoca era difficile immaginare cosa potesse farsene una persona di un computer in casa. Egli invece continuò per la sua strada fondando Apple Computer Inc. il 1º aprile 1976 assieme a Steve Wozniak e Ronald Wayne. Jobs era convinto che il futuro del personal computer sarebbe stato legato all'interfaccia grafica. E così, ispirandosi a quella sviluppata da Xerox Corporation qualche anno prima, Apple lanciò nel 1984 Mac OS il primo sistema operativo per personal computer con interfaccia grafica. Questa fu una vera rivoluzione tanto che nello stesso anno sarebbe nato l'X Window System in ambiente Unix e il 20 novembre 1985 Microsoft avrebbe commercializzato Windows. All'inizio Windows non era definibile come un sistema operativo: era piuttosto un'estensione di MS-DOS. Fu con il rilascio di Windows 3.0, nel 1990, che Microsoft si impose sul mercato. Oltre alle maggiori performance che garantiva alle applicazioni rispetto alle versioni precedenti, Windows 3.0 forniva un ambiente multitasking migliorato rispetto alle precedenti versioni di MS-DOS, grazie all'introduzione del supporto alla memoria virtuale, e divenne così un degno rivale dell'Macintosh (su cui girava Mac OS) di Apple. A partire da Windows 3.1 fu introdotto il supporto alla multimedialità (perfezionato via via nelle successive release), mentre con l'introduzione di Windows 95 si passò definitivamente dal calcolo a 16 bit a quello a 32 bit. 7 I sistemi operativi di rete e il fenomeno Linux A fianco di Microsoft ed Apple il mercato delle workstation e dei grandi elaboratori era comunque dominato da UNIX. Un fenomeno interessante che iniziò a prendere piede da metà degli anni ottanta fu lo sviluppo delle reti di calcolatori, fenomeno che ha poi portato all'incredibile crescita di Internet. Nacquero così i "sistemi operativi di rete" e i "sistemi operativi distribuiti". I primi altro non sono che normali sistemi operativi ai quali vengono aggiunti i software per il collegamento a macchine remote e quindi alle relative risorse condivise come file e stampanti. I secondi sono sistemi operativi che girano su sistemi a più processori oppure che inviano i processi da elaborare ad altri computer della rete. Essi sono dotati di particolari politiche di scheduling che permettono una efficace allocazione dei processi tra le CPU disponibili. Inoltre anche il sistema di archiviazione (il file system) è unico, anche se in realtà è distribuito tra vari nodi della rete. Esempi della prima classe di sistemi di rete sono tutte le versioni di Windows dalla "Windows for Workgroups 3.1" e dalla "NT" in poi, mentre UNIX e derivati fanno parte di entrambe le categorie in quanto supportano entrambe le tecnologie. Nel 1991 Linus Torvalds sviluppò un kernel Unix-like, capace però di girare sulla piattaforma x86. Così nacque Linux. Fu quando venne abbinato al progetto GNU di Richard Stallman, portavoce della filosofia del software libero, che iniziò la fortuna di GNU/Linux in quanto la combinazione risultava, e lo è tuttora, un sistema operativo efficiente ed affidabile. 8