2.04 Lezione 4 - follen99/ArchitetturaDeiCalcolatori GitHub Wiki

Servizi di Sistema

Esiste una grande varietà di programmi di sistema che permettono di gestire i file, come copia, Rename, stampa ecc. Per quanto riguarda le informazioni di stato, esistono dei servizi che permettono di accedervi, e che quindi permetto di accedere ad informazioni come data, ora ecc.

Questi programmi di sistema stampano l'output del sistema sul terminale o altri Devices, per permettere all'utente di consultarli.

Registry

Alcuni sistemi implementano un registry, tipico dei sistemi Windows odierni.

Sistemi Windows

L'idea era quella di usare un deposito unico in cui conservare tutte le informazioni di configurazione di sistema, in modo da avere sempre pronte queste informazioni. Il problema fuoriesce nel momento in cui vogliamo disinstallare un programma che utilizza il registry, perché ci

Sistemi Unix

Nei sistemi Unix, invece di avere un unico file dove vengono conservate tutte le informazioni, esiste una directory apposita, chiamata etc, in cui, racchiuse all'interno di diverse directory, sono presenti tutte le informazioni di sistema. Tutti questi file sono sotto forma di file di testo, quindi completamente analizzabili dall'utente.

Supporto per linguaggi di programmazione

Alcuni sistemi operativi forniscono degli strumenti per sviluppatori, come compilatori, assemblato, sistemi di debuggano ecc.

Servizi di background

Oltre ai programmi che vengono lanciati dall'utente, qualsiasi SO lancia dei servizi in background, ovvero dei programmi che restano in attesa di essere utilizzati. Nel mondo UNIX questo tipo di programma è chiamato Deamon. Nel mondo Windows invece sono chiamati Services.

Linkers e Loaders

  • Un Linker è un software che unisce tutti i file oggetto a disposizione, in maniera da ottenere un eseguibile binario completo.
  • Un Loader è in grado di prelevare un eseguibile dal disco e gli assegna un indirizzo di memoria per essere eseguito.

Bonus

Il comando MAN su UNIX è suddiviso in sezioni. La sezione 1 è quella destinata ai programmi di sistema, e non alle syscalls. Per cui se si volesse accedere alla syscall dovrebbe digitare: man -S 2 open.

Inoltre, per "uccidere" un processo su unix basta digitare ps, controllare il il PID del processo ed usarlo per chiudere il processo con kill -9 2793.

Perché le applicazioni sono tipiche del sistema operativo?

Posso prendere un determinato programma scritto per un determinato processore, su un determinato sistema operativo, ed eseguirlo sulla stessa macchina ma con SO diverso? Ovviamente la risposta è NO.

Posso trasferire una libreria, in formato già compilato, ed utilizzarla sulla stessa macchina con SO diverso? Anche in questo caso la risposta è NO.

  • Compatibilità del formato dell'eseguibile: il formato con cui viene creato il binario, è diverso da SO a SO.
  • System calls diverse: anche le System calls sono diverse.
  • Parametri delle Syscalls diversi: anche i parametri, da passare con le chiamate di sistema, variano da SO a SO.

Non è possibile, quindi, far eseguire lo stesso programma, anche sulla stessa macchina, con due Sistemi operativi diversi.

Come risolvere il problema

Emulazione

É possibile eseguire, ad esempio, un programma windows su sistema Linux. Si può fare ciò attraverso l'uso degli emulatori. Un Emulatore (ai tempi veniva usato Wine-Windows emulator) che al momento dell'esecuzione del programma, intercettava tutte le syscalls del programma, trasformandole in syscalls di linux. Il problema è che microsoft (che aveva scritto il programma da emulare) aveva usato delle syscalls non note, e di conseguenza non era possibile effettuare la conversione delle syscalls.

Virtualizzazione

Il problema viene in realtà risolto con l'emulazione, ovvero eseguendo, all'interno di Linux, una sessione di Windows, dove verrà eseguito il programma nitidamente.

Come si progetta un Sistema Operativo?

Esistono dei criteri di progetto che rendono il processo "semplice"? Risposta veloce: No.

Fondamentalmente la struttura interna di un SO può variare, ed anche di molto, da SO a SO. Anche nello stesso mondo Unix, la struttura interna cambia moltissimo.

Obbiettivi quando si sviluppa un SO

Quando si sviluppa un sistema, ci sono due obbiettivi principali:

  • Obbiettivi di Utente : Il sistema dovrebbe essere di facile utilizzo, facile da comprendere, affidabile sicuro e veloce.
  • Obbiettivi di Sistema : Il sistema dovrebbe essere semplice da progettare, implementare e sopratutto efficiente.

Come si nota, gli obbiettivi non coincidono completamente, infatti l'utente finale è poco interessato a sapere che il SO sia efficiente, ma il suo interesse è quello che esso sia veloce ed affidabile.

Principio più importante

Nel progetto di una qualsiasi cosa, bisognerebbe distinguere "ciò che voglio fare" e "qual è il modo per farlo". Dovrei ragionare sulla politica, ovvero il risultato che voglio ottenere, senza farmi influenzare fin dall'inizio dalla modalità con cui implementerò.

In poche parole, questo concetto ci permette di progettare il nostro obbiettivo, senza farci influenzare dalle problematiche del "come realizzarlo". In questo modo, gli obbiettivi, e quindi le funzioni, rimarranno gli stessi nel tempo, anche se l'implementazione potrà cambiare.

  1. Decidere cosa voglio che il mio software faccia
  2. Impazzire, solo dopo, per implementarlo

🏁 00:34 05-06

Implementazione (dei sistemi operativi)

I primi SO venivano implementati rigorosamente in assembly, dopodiché sono stati utilizzati dei linguaggi come l'Algol, che permettevano di scrivere SO.

Infine, usato ancora oggi, venne impiegato il C, C++. In effetti, il C venne proprio creato per lo sviluppo di sistemi operativi, per via del bisogno di avere un linguaggio che fosse a basso livello, ma che allo stesso momento permettesse di eseguire operazioni complesse.

Mix di Linguaggi di programmazione

I SO, in verità, sono composti da un mix di linguaggi. Infatti i livelli più bassi del SO vengono scritti in linguaggio macchina, e quindi in assembly, per via della manipolazione dei registri, il corpo principale viene scritto in C, per le motivazioni già spiegate precedentemente, ed infine i programmi di sistema possono essere scritti, ancora una volta, in vari linguaggi, come il C, C++, linguaggi di scripting come Python e Shell.

Come è strutturato un Sistema Operativo

Fondamentalmente i sistemi più antichi, programmati in modo tale da occupare una piccolissima quantità di memoria, avevano una struttura molto semplice; era il caso di MS-DOS. Altri sistemi sono invece più complessi, come UNIX.

Struttura Monolitica - UNIX originale

In questi sistemi è presente una struttura di vari moduli software, ma il kernel è unico. Ciò significa che non solo il kernel è un'unico pezzo, ma che esso viene eseguito in modalità supervisore.

img

Approccio a "strati"

Negli anni è stato suggerito di strutturare il SO a livelli: img

Questa è una struttura molto "comoda" sulla carta, ma nella pratica non funziona molto bene, perchè tra un'operazione e l'altra c'è il bisogno di effettuare dei "salti" tra uno strato e l'altro.

Per questo motivo non esiste un SO che adotti questa struttura.

Microkernel

Il microkernel è "l'avversario" della struttura monolitica. Questo perchè nel kernel resta solo il minimo indispensabile come:

  • Scheduling della CPU: perché serve all'esecuzione di processi
  • Gestione della memoria
  • Comunicazione tra processi

Tutto il resto, vengono eseguiti come Programmi di sistema, in User mode. L'idea è la seguente: "cerchiamo di levare quanta più roba possibile dal kernel, facendolo eseguire come programma di sistema". Il vantaggio ottenuto, oltre al fatto di avere un kernel molto compatto, è sopratutto il fatto che molte attività vengono eseguite in modalità utente; questo significa che se è presente un guasto o malfunzionamento, non è possibile fare "danni". In questi casi basta semplicemente rilanciare il processo, ed il sistema continua a funzionare senza problemi.

Con questo schema, come già detto, nel kernel è posto solo il minimo indispensabile, il resto invece viene fatto mediante l'invio di "messaggi", ovvero i programmi di sistema comunicano tra loro grazie all'interprocess communication, situato nel kernel.

Il primo sistema strutturato su microkernel era il sistema Mach, che nella sua prima versione era molto lento. Questo perchè scambiare dei messaggi non è veloce come cambiare una funzione all'interno del kernel stesso, e quindi, per i processori di una volta, avere un sistema a Microkernel, voleva dire rallentare l'esecuzione.

Fun fact

Linux è stato strutturato in modo "monolitico", nonostante inizialmente si era insistito per utilizzare un approccio a microkernel, che però non venne ben visto dai primi sviluppatori. Anche Windows è basato su una struttura Monolitica. La differenza principale tra i due sistemi è che in linux l'interfaccia grafica gira in modalità utente, mentre in windows in modalità supervisore.

Quale OS usa il microkernel?

L'unico SO moderno (ampiamente utilizzato) che è basato su una struttura a microkernel, è Mac OS, basato sul sistema Mach.

Fine capitolo 2 🏁 01:01 05-06

Capitolo 3 : i Processi

Un sistema operativo esegue una varietà di programmi, i programmi in esecuzione vengono detti processi. C'è una distinzione tra programma e processo:

  • Programma: entità STATICA
  • Processo: entità DINAMICA

Memoria usata da un programma

Quando il programma va in esecuzione, viene eseguito sequenzialmente istruzione per istruzione, ed ha uno spazio indirizzi a disposizione, suddiviso in:

  • Text Section, ovvero il codice del programma
  • Program Counter
  • Stack, che contiene data temporanea
  • Data section, che contiene le variabili globali
  • Heap, che contiene memoria allocata dinamicamente durante il tempo di esecuzione.

Esecuzione di un programma

Stato NEW

Lo stato "new" è presente in sistemi che hanno capacità di batching, quindi non è presente in sistemi come windows. In questo caso, il SO prende atto della presenza di un programma che deve essere eseguito, situato in una coda. Il programma ci rimane finché non viene ammesso, e quindi si sposta allo stato ready.

Stato READY

Quando mandiamo in esecuzione un programma, questo riceve dal SO spazio in memoria, viene inserito nella lista dei programmi che utilizzano la CPU. Questo stato viene chiamato READY, proprio perché il programma è pronto per essere eseguito. Questo vuol dire che è presente in memoria, ma non ha ancora ricevuto la CPU per andare in esecuzione a tutti gli effetti.

OPERAZIONE DI DISPATCH

In un sistema tradizionale, dotato di di un'unica CPU, la gran parte dei processi sono nello stato Ready, mentre è presente un unico processo in esecuzione. Prima o poi, il SO darà la possibilità ad un altro processo (nello stato ready) di essere eseguito. Questa operazione viene chiamata dispatch, quindi lo scheduler è quella parte del SO che decide qual è il prossimo processo da mandare in esecuzione.

Stato RUNNING

In questo stato il processo in quell'istante è in esecuzione. Esso resta in esecuzione finché non avviene una delle seguenti cose:

  1. Il processo termina volontariamente, ovvero esegue una syscall Exit, quindi si sposta nello stato exit.
  2. Arriva un'interrupt, che potrebbe provenire dalle periferiche, come ad esempio la pressione di un tasto da parte dell'utente, oppure un Interrupt di timer, ovvero quando il processo è stato troppo tempo in esecuzione e quindi ne viene scelto un altro per l'esecuzione.
    Un'altra possibilità di Interrupt potrebbe essere quella dell'attesa di input da parte dell'utente, quindi il processo perde la CPU, e va nello stato di attesa. Il processo puo uscire dallo stato di attesa in due casi:
  3. Viene completata l'operazione di I/O
  4. L'eventuale timer che lo ha fatto spostare nello stato di attesa finisce.

Process control block

Quando un processo è in esecuzione il SO deve prenderne atto, e quindi gestire delle informazioni relative a quel processo. Quindi, siccome il SO ha a disposizione delle informazioni per ogni processo ammesso, si dice, in maniera astratta, che è presente un blocco di controllo dei processi.

Anche se queste informazioni non risiedono tutte nello stesso punto, sono sempre presenti:

  • Stato del processo: running - waiting - ecc
  • Program Counter: posizione della prossima istruzione da eseguire
  • Registri CPU: contenuti di tutti i registri del processo
  • Informazioni di scheduling CPU: priorità, puntatori a code di scheduling
  • memoria: informazioni sulla memoria allocata dal processo
  • Informazioni di accounting: CPU utilizzata, tempo passato dall'esecuzione, utilizzato nei sistemi a pagamento per tenere traccia del tempo di CPU usato per poi calcolare un pagamento.
  • Informazioni sullo stato di I/O: lista di files aperti ecc.

Threads

Un processo, ha un program counter, e quindi esegue codice in maniera sequenziale. Negli ultimi anni si è diffuso sempre di più l'utilizzo di tecniche di threading. Questo significa che esiste la possibilità di più esecuzioni di codice, contemporaneamente.

🏁 1:35 05-06

Scheduling dei processi

Il SO deve Schedulare i processi ed alternarli, in modo tale che la CPU sia quanto più utilizzata possibile. La parte del SO che si occupa di queste operazioni, è proprio il Process Scheduler, che seleziona tra i processi in attesa di esecuzione tra una coda.

Questi processi sono posti in apposite strutture dati molto efficienti, in modo da avere sempre a disposizione il prossimo processo da eseguire.

processo

Context Switch

Le operazioni che fermano un processo e ne attivano un altro, sono dette context switch; nel momento in cui il SO decide di fermare un processo per attivare il prossimo della coda, salva lo stato di program counter e registri del processo precedente, e ne manda un altro in esecuzione.

Siccome questo switch richiede del tempo di CPU, deve essere il quanto più veloce ed ottimizzato possibile. Questo tempo dipende sopratutto dall'hardware, perchè più registri ci sono da salvare, maggiore sarà il tempo dell'operazione.

Inoltre, questa parte di codice (del context switch) è scritta in assembly, proprio perché è l'unico codice che ci permette di maneggiare i registri, oltre al fatto che l'assembly ci permette di scrivere un codice molto ottimizzato e veloce.

🏁 fine lezione 4


⚠️ **GitHub.com Fallback** ⚠️