capitolo 13 - microkernel
Transcript
capitolo 13 - microkernel
CAPITOLO 13 - MICROKERNEL MICROKERNEL Questo learning object si occupa del microkernel che è un altro concetto base dei moderni sistemi operativi. MICROKERNEL Nella slide sono riportate due architetture. La prima è riferita ai primi sistemi operativi dove le diverse parti del sistema erano stratificate e si passava di strato in strato dall’hardware allo spazio utente attraverso la gestione di base dei processi, la gestione della memoria virtuale, la gestione dei dispositivi di I/O, la comunicazione interprocesso, la gestione del file system e poi si giungeva allo spazio utente. Allo scopo di trasformare i comandi diretti a sistema, in altrettanti processi di sistema, un’interfaccia con lo spazio utente chiamata shell provvedeva a raccogliere i comandi di sistema. Era la struttura del vecchio OS/360 che comprendeva ben 1.000.000 di linee di codice scritti in cinque anni da 5.000 progettisti, ma anche quella di Multix che era giunto ad includere ben 20.000.000 di linee di codice. La seconda architettura è quella a microkernel di un moderno sistema operativo dove vediamo che immediatamente sull’hardware si trova un microkernel a cui i vari moduli del sistema operativo (chiamiamoli client) si riferiscono in modalità utente per ottenere servizi da altri moduli (chiamiamoli server) sempre del sistema operativo. Una struttura verticale è stata sostituita da una struttura orizzontale e tutti i moduli comunicano tra di loro attraverso il microkernel. In questo modo si realizza un’architettura client/server. BENEFICI DI UNA ORGANIZZAZIONE MICROKERNEL - Interfaccia uniforme:servizi del kernel e servizi utente utilizzano tutti gli stessi segnali. - Estensibilità: estensione di nuovi servizi facilitata (vedasi per es.dischetti con nuove organizzazioni dei file gestite a livello utente). - Flessibilità:a secondo delle applicazioni certe caratteristiche possono essere ridotte o potenziate (vedasi la sicurezza). - Portabilità: Il cambio dell’hardware comporterà unicamente la modifica del microkernel. - Affidabilità: l’organizzazione modulare permette di realizzare sistemi più affidabili e ai programmatori di conoscere un minor numero di API. - Supporto ai sistemi distribuiti: ogni servizio è identificato da un numero nel microkernel e una richiesta da client non è necessario che sappia dove si trova il server in grado di soddisfare la stessa. - OOOS: (Object Oriented Operating Sistems).(Parzial. Windows NT) Prestazioni del MICROKERNEL Ogni messaggio a microkernel richiede cambiamento di stato Utente-kernel il Questa slide riporta alcune considerazioni sull’uso del microkernel mettendo in evidenza che poiché ogni chiamata di servizio deve passare dal microkernel, sarà necessario un cambiamento di modalità e come sappiamo questo ha un costo in termini di Siccome tutto passa per il microkernel il gran sovraccarico. Se avvengono molte chiamate di sistema, come numero di cambiamenti può far decadere il accade naturalmente per il tipo di architettura che stiamo sistema. mostrando, può aversi un decadimento del sistema. La soluzione parziale usata recentemente è di ridurre il numero di chiamate a Recente soluzione: sistema che è passato da 140 a 7 chiamate con conseguente Ridurre il microkernel ridimensionamento da 300 Kb a 12 Kb del microkernel e con tutti 300 Kb 140 chiamate a sistema i vantaggi in termini di modularità e quindi d’affidabilità, 12 Kb 7 chiamate a sistema portabilità, e sicurezza. Alcuni test hanno mostrato che è possibile si sono ottenute le stesse prestazioni di un sistema ottenere con le strutture a microkernel le stesse prestazioni di un a strati UNIX sistema stratificato UNIX. 1 Progettazione del MICROKERNEL Un insieme minimo di funzioni e servizi del microkernel per supportare server e applicazioni utente deve includere: • gestione primitiva della memoria • comunicazione tra processi (IPC - Inter Protocol Communication) • gestione interrupt ed I/O La progettazione di un microkernel deve includere un insieme minimo di funzioni e servizi che devono includere: - la gestione primitiva della memoria; - la comunicazione tra processi; - la gestione dell’interrupt e dell’I/O. Nel seguito vediamo nei particolari questi tre aspetti. GESTIONE PRIMITIVA DELLA MEMORIA In questa slide sono riportate le parti importanti della gestione primitiva della memoria. Il thread di un’applicazione fa richiesta di una locazione di memoria ma non essendo in memoria genera un page fault e l’esecuzione salta al microkernel. Il microkernel chiede al paginatore di liberare spazio in memoria principale (Grant), quindi trasferisce la pagina necessaria in memoria principale (Map) e alla fine rilascia la pagina (Flush). E’ chiaro che la concessione di spazio per allocare una pagina sarà fatta con qualche particolare algoritmo (LRU). Comunicazione tra Processi o tra Thread La base della comunicazione è il messaggio La base della comunicazione tra processi è il messaggio. Ogni messaggio include il Messaggio e (intestazione)+(corpo)+(puntatore a inform.controllo) processo mittente e il processo ricevente che costituiscono l’intestazione del - (intestazione) (include Mittente, Ricevente) messaggio, i dati da trasferire detto corpo - (corpo) (contiene i dati del messaggio) del messaggio, un puntatore ad un blocco di - (puntatore) (a un blocco di dati di controllo del processo PCB) dati di controllo del processo vedasi (PCB). La comunicazione avviene attraverso porte il messaggio è intercettato dal microkernel a cui vengono accodati i messaggi per quel • (capability list)(include i processi da cui si accettano messaggi) processo. Ogni porta ha associata una • Per ogni processo c’è una porta associata attraverso cui arrivano capability list che dice quali sono i processi i messaggi (il messaggio è messo nella coda dei messagi di quel tipo) abilitati a comunicare col processo. I L’accesso alla capability list può essere controllata via microkernel messaggi sono accodati nelle liste. Ogni processo può inviare al kernel la nuova accessibilità. Gestione dell'Interrupt ed I/O Il microkernel trasforma l’interrupt in messaggio a livello utente, pertanto il microkernel riconosce gli interrupt ma non li gestisce direttamente. Quando un interrupt abilitato viene accettato, il mKernel gli assegna il relativo programma mappandolo. I processi relativi ad interrupt generalmente hanno più alta priorità. Così ad esempio gli interrupt di I/O si trasformano in processi di trasferimento. Ovviamente anche in questo caso è il microkernel che mappa i programmi relativi alle azioni di I/O. In un’architettura microkernel è possibile gestire gli interrupt hardware come messaggi e contenere le porte di I/O nello spazio di indirizzamento. In altre parole un’interrupt è riconosciuto dal sistema ma non è gestito direttamente cioè il microkernel trasforma l’interrupt in un messaggio a livello utente. Quando un interrupt viene abilitato il kernel mappa il relativo programma. Quando l’interrupt si verifica è il kernel che gli associa il relativo messaggio. 2 Gestione dell'Interrupt ed I/O Lied ha suggerito di vedere l’hardware come thread con identificatori unici e mandando messaggi ai thread associati di livello utente. La slide riporta la routine del thread del livello utente. Windows NT - Thread e SMP Windows NT fornisce supporto ad ambienti di sistema diversi nei quali i processi differiscono: -per come sono chiamati; -per la presenza o meno di thread al loro interno; -per come sono rappresentati; -per come sono protette le loro risorse; -per i meccanismi di comunicazione interprocesso; -per come sono correlati i processi. Windows NT fornisce supporto a vari sistemi operativi, da MS DOS e Posix a Win 32 e a OS2. Alcuni usano solo processi e altri thread. Ognuno ha un modo diverso di rappresentare le strutture dati, un suo modo di proteggere le risorse, i suoi meccanismi di comunicazione tra processi, un modo diverso di correlare i processi. Windows NT I processi di NT sono implementati come oggetti, ogni processo può incorporare più thread, thread e processi hanno la capacità di sincronizzarsi tra di loro. Nella slide è mostrata la struttura di un processo. Quando il processo viene creato, il suo genitore gli assegna un token di accesso (token primario) che costituisce il meccanismo per la protezione dell’accesso al processo, infatti nella creazione del token gli viene dato l’identificativo unico che poi passa nel PCB e insieme anche i diritti. Il processo non ha la possibilità di modificare i diritti d’accesso che sono nel token, gli sono stati passati e basta, sono stati creati con l’identificazione dell’utente e se li passano di padre in figlio. All’atto della creazione il gestore della memoria virtuale gli assegna, come si vede in figura, una serie di blocchi. Tra questi c’è quello di un thread, il primo creato da Windows per quel processo, ovviamente man mano che ne vengono creati altri questi si accodano alla serie dei blocchi assegnati al processo, c’è un blocco per i file, uno per l’area condivisa. Per accedere ai blocchi il processo fa uso di una tabella degli oggetti e ai diversi oggetti accede attraverso una maniglia (handle), che permette di puntare la parte di memoria contenete l’oggetto. Nella figura è anche riportata una handle per la section z che la sezione di memoria condivisa attraverso la quale i processi e i thread si scambiano messaggi. 3 Descrizione degli Oggetti tipo Processo in Windows NT Un oggetto processo ha i suoi attributi e i suoi metodi ossia i servizi che è in grado di svolgere. Nella slide sono riportati gli uni e gli altri. E’ importante notare che nella sezione degli attributi c’è la porta per le eccezioni attraverso cui passeranno i messaggi, per esempio delle page fault, quella per la terminazione ecc… Le altre voci della sezione attributi si commentano da sole, ma è utile richiamare l’attenzione sulla voce Contatori delle operazioni di MV. Nella parte sottostante sono invece riportati i servizi. Qui è utile notare la quantità di servizi per la memoria virtuale, cosa che non troveremo nei metodi per gli oggetti thread, proprio perché la differenza sostanziale tra thread e processi è la presenza o meno di risorse. Descrizione degli Oggetti tipo Thread in Windows NT In questa slide sono invece riportati gli attributi di un oggetto thread e i metodi corrispondenti. Si può osservare che invece del contatore di I/O qui c’è il contatore di sospensione perché è il kernel che provvederà a fare l’I/O e il thread si limiterà ad essere sospeso o terminato, c’è anche uno stato di allerta per quando il thread attende un messaggio. Alcuni metodi sono analoghi a quelli dei processi ma non ci sono più tutti i servizi della memoria virtuale invece, ci sono molti servizi esclusivamente riferiti ai thread. 4 Descrizioni Processo e Thread di Windows NT a confronto Per dare risalto alle differenze e sottolineare le differenze tra processi e thread in questa slide le due tabelle sono messe a confronto. Creazione di un processo in Windows NT Per LA CREAZIONE DI UN PROCESSO Windows NT: 1) usa la classe 0-tipo dell’oggetto; 2) vengono assegnati i valori degli attributi. Una descrizione dettagliata degli attributi di un processo è riportata nella slide. Nella slide è anche sottolineato che all’atto della creazione il sistema usa la classe 0 di oggetto e definisce il tipo di oggetto che in questo caso è un processo, quindi gli passa i valori degli attributi. 5 Creazione di un Thread in Windows NT • Quando un processo viene creato la prima cosa che fa è di creare almeno un thread; • Nella creazione, il processo passa al thread gli attributi di cui a fianco. In questa slide è invece messo in evidenza che come un processo viene creato viene subito creato un thread e nella creazione per ereditarietà molti attributi vengono passati dal processo al thread. Nella slide è anche riportato il significato dei vari attributi dei thread. Multithreading in Windows NT • NT supporta la concorrenza; • Il sovraccarico dovuto alla concorrenza può essere eliminato usando un’architettura multi-processore; • Un processo multithread ad oggetti è il modo più efficiente di realizzare una applicazione server, in questo caso ogni client crea un thread del server. In questa slide è invece sottolineata la particolare struttura multithreading di Windows NT con i maggiori vantaggi che ne derivano. Stato dei thread in Windows NT • Standby è legato alla disponibilità del particolare processore richiesto per il thread. • Waiting da running il T o va da solo in W oppure se la priorità di un altro T è più alta il processo in running può essere interrotto. • Transition si ha quando dopo il waiting si scopre che le risorse non sono disponibili (stack swaped). A partire da questa slide si riportano invece le descrizioni degli stati dei thread rispettivamente in Windows in questa ed in Solaris nelle successive. In questa sono riportati i sei stati di un thread di Windows NT. In particolare: I tre stati eseguibili sono Ready, Running e Standby. I primi due non hanno bisogno di commento, nello stato standby un thread si porta quando non è disponibile il processore di affinità richiesto. Nella parte inferiore della slide ci sono invece altri tre stati non eseguibili di cui waiting è quello in cui il thread si porta o volontariamente per aspettare che si verifichi un evento ( wait (semaforo) ) oppure perché è stato forzato da altri (sottosistemi) a portarsi perché accade qualche altra cosa (I/O). Se quando l’evento è accaduto le risorse sono ancora disponibili allora va in ready altrimenti (vedi uno stack non più disponibile) va in transition da cui poi andrà a ready. Infine da running il thread va in terminated da cui viene rimosso o conservato per essere disponibile per altri processi. 6 Supporto ai sottosistemi di Windows NT E’ responsabilità dei sottosistemi sfruttare le caratteristiche dei thread e dei processi di NT per emulare thread e processi dei sistemi operativi corrispondenti. Un’applicazione fa richiesta ad un certo sottosistema di creazione di un nuovo processo, la richiesta dal sottosistema protetto va a windows NT. Nel caso di Win 32 ed OS 2, dovendosi creare un thread la richiesta ritorna nuovamente a Windows NT per la creazione del thread. Quindi il processo viene restituito all’applicazione. SMP Windows NT executive dà il supporto ai sottosistemi di ambiente. Quando l’applicazione invia ad un sottosistema la richiesta di creare un processo, e quindi gli passa il token, questo invia ad executive la richiesta perché sia creato in NT il corrispondente processo. Se la richiesta è a WIN 32 o OS2, con la creazione del processo, NT crea un thread (attraverso un meccanismo di richiamata tra sottosistema ed NT), viene definito l’handle di quel thread e passata al sottosistema. Se invece la richiesta è a Win 16 o POSIX accade che il thread viene creato a livello NT executive ma il sottosistema non ha conoscenza. Nella creazione del thread è il processo client che trasferisce al thread i valori degli attributi (limite di quota, priorità di base, affinità di processori) in modo che il thread li eredita dal client e non dal server. NT supporta anche il SMP. Seguendo il meccanismo delle affinità deboli o forti, NT manda in esecuzione più thread sui diversi processori della macchina. Nel caso di affinità deboli il thread torna sullo stesso processore su cui era in esecuzione in precedenza per ritrovare dati già presenti nelle cache, in caso di affinità forti il sistema può restringere l’insieme dei processori su cui il thread può andare in esecuzione. Thread e gestione del SMP in SOLARIS Architettura multithread stratificata - Thread di livello utente (gestiti dalla libreria Utente) Processi Leggeri - Thread di Kernel L’architettura dei processi e thread in Solaris è stratificata e passa dai thread a livello utente (gestiti dalla libreria utente) ai processi leggeri (novità di Solaris), ai thread di livello kernel. La successiva slide dà una rappresentazione di questa stratificazione. Esempio di architettura multithread in SOLARIS Nella slide sono rappresentati cinque processi P concorrenti, ognuno con il relativo PCB, uno spazio per il programma e i dati, e uno spazio per lo stack del kernel. Essi corrispondono a cinque processi del livello utente. In alto sono rappresentati i thread di livello utente di ciascuno dei processi. I thread li crea la libreria, come avveniva per SVR4. E’nello spazio utente che i thread si scambiano messaggi per effettuare la multiprogrammazione a livello utente. I vari thread si rapportano a processi leggeri. Ogni processo leggero è in connessione diretta, in rapporto uno 7 ad uno con un thread kernel. I thread kernel interagiscono poi con il sistema attraverso i processi. A livello kernel è anche data la possibilità dell’esecuzione parallela dei thread kernel ivi compresa l’esecuzione parallela su processori differenti SMP. Può essere analizzato uno per uno il grado di parallelismo dei singoli processi riportati nell’esempio della figura. Perché Solaris preferisce passare attraverso i processi leggeri piuttosto che andare direttamente ai processi? Perché, evidentemente, i processi hanno strutture pesanti (si pensi a tutte le strutture dati per la gestione di risorse che devono comprenderle tutte e per tutti i processi).I processi leggeri, invece, essendo confinati all’interno di un processo non avranno bisogno delle strutture di tutte le risorse, con conseguente riduzione del carico per il cambio. Tutti i thread kernel che il sistema crea e distrugge non sono riportati in figura, solo quelli direttamente rapportati al livello utente sono illustrati. Struttura dati dei Processi nei vecchi UNIX/e/in SOLARIS Questa slide descrive la struttura dati dei processi. A sinistra c’è la struttura dati per Unix tradizionale, a destra le modifiche introdotte nelle strutture dati di Solaris. Come si vede, la tabella di stato del processore è sostituita con una LISTA DI tabelle relative allo stato dei singoli processi leggeri, ognuno contiene: - un identificatore del processo leggero; - la priorità con cui viene eseguito; - una maschera dei segnali che vengono accettati; - i valori salvati dei registri quando il processo leggero non è in esecuzione; - lo stack del kernel; - l’utilizzo delle risorse e i dati di monitoraggio; - il puntatore al thread del kernel; - un puntatore alla struttura del processo. Esecuzione dei Thread (ULT) (4 azioni che portano al cambiamento di stato) • Sincronizzazione (segnali di sincronizzazone T Un thread di livello utente in esecuzione, in Solaris, passa (Active>Sleeping)) attraverso gli stati di Runnable, Active, Sleeping e Stopped. • Sospensione (per azione dello stesso thread T Questi stati sono riportati nella figura successiva a questa. (Active>Stopped)) In questa slide anticipiamo per facilitare la comprensione • Prelazione (un T’ a priorità più alta sospende T quali sono le azioni che portano ad un cambiamento di Attivo (Active > Runnable)) stato dei thread del livello utente. Sono appunto dovute a • Concessione (con thr_yield da T viene creato T’ sincronizzazione, a sospensione, a prelazione, che diventa active perché va sul processo leggero di T) concessione. 8 SOLARIS: STATI e DIAGRAMMI Sincronizzazione / Sospensione/ Prelazione/ Concessione (thr_yield) /// THREAD ed INTERRUPT In questa slide è riportato il diagramma delle transizioni tra stati di un thread di livello utente con il collegamento al processo leggero a cui è collegato. Come si è già visto un thread in stato active è associato ad un processo leggero che corrisponde a sua volta ad un thread kernel. A questo thread di livello utente può accadere una delle azioni già anticipate nella slide precedente e cioè: -Sincronizzazione: il thread esegue una primitiva di sincronizzazione e non essendosi verificate date condizioni deve passare nello stato sleeping. Quando la condizione si verifica, il thread passa da sleeping a runnable. Dallo stato runnable, non appena il processo leggero si libera, ed il thread viene schedulato, passerà di nuovo active nello stato di running. -Sospensione: Il thread essendo attivo, accade che qualche altro thread o esso stesso lo fermano, allora va in stopped. Può essere poi rimosso da questo stato per passare in runnable quando gli viene inviato un messaggio di continuazione. -Prelazione: un thread fa passare in stato runnable un altro thread a priorità più alta, allora il thread in running viene interrotto e passa in stato runnable. Quello a più alta priorità diventa attivo e passa in running. -Concessione: Quando un thread esegue il comando di libreria thr yield viene preso un altro thread di stessa priorità a cui viene assegnato il processo leggero. Se la trattazione fin qui fatta ha dato priorità al thread di livello utente, nella parte bassa della figura sono descritte le transizioni dei processi leggeri. Se un thread in running ha esaurito il suo slice, passa da running a runnable e quando torna il suo turno ritorna in running. Se si verifica una azione bloccante passa in blocked e da questo stato con un risveglio passa nuovamente in runnable, ma può anche accadere che da blocked possa passare in stopped e così via come mostrato in figura. E’ una chiamata a sistema bloccante che porta il processo leggero nello stato blocked. E’ evidente che la chiamata a sistema bloccante è altamente probabile che la generi il thread kernel alle spalle del processo leggero. Si sottolinea, in conclusione, che questa trattazione fa riferimento a processi leggeri multithread di livello utente con assegnazione di un unico processo leggero ai thread. Inoltre, è conveniente distinguere per il caso delle transizioni tra stati dei processi leggeri, il caso di thread liberi e il caso di thread legati al processo leggero. INTERRUPT COME THREAD Se la slide precedente ha chiarito l’uso e la relazione tra ULT e processi leggeri (LWP), la domanda che viene naturale ora è come sono organizzati i KLT di Solaris? Unificando thread kernel e interrupt e gestendoli con i meccanismi della mutua esclusione e della sincronizzazione ordinaria ma provvedendo ad effettuare un mascheramento e l’assegnazione di livelli di priorità ai vari thread. Ad esempio il sistema può inibire interrupt a tutti i processori di un sistema multiprocessing! Se fino ad ora ci si è addentrati nella trattazione dei thread utente e processi leggeri a questo punto viene naturale la domanda, ma come sono fatti i thread kernel dell’altro strato sottostante in Solaris? I processi di sistema e gli interrupt in Solaris vengono visti e gestiti alla stessa maniera, tutti attraverso thread kernel. Ogni thread ha un identificativo una priorità un contesto uno stack. Tutti i thread avanzano concorrente mente, con i normali meccanismi di sincronizzazione e mutua esclusione che si vedranno nelle lezioni successive come l’uso di semafori, di primitive di sincronizzazione quali wait, signal, scambio, test and set e algoritmi vari. In particolare in Solaris le varie richieste possono essere mascherate per essere accettare o ignorate, siano esse per interrupt siano esse per thread kernel. E’ notevole che la priorità dei thread kernel può essere scalata e i thread relativi ad interrupt hanno normalmente priorità più alta degli altri thread. 9