Sottosistema di Input/Output (I/O)
componente del sistema operativo, responsabile della gestione ottimizzata dei flussi di dati tra le applicazioni e le periferiche
Tipi di Periferiche
Le periferiche hardware si dividono in due principali categorie:
- Device a blocchi
- Gestiscono dati in gruppi di byte
- Sono dotati di buffer integrati per ottimizzare la lettura e la scrittura
- Esempio: dischi rigidi, SSD
- Device a caratteri
- Gestiscono dati un byte alla volta
- Esempio: tastiere, stampanti
Componenti Hardware per l’I/O
Per gestire il trasferimento di dati tra periferiche e il sistema, esistono componenti hardware specializzati:
- Controller:
- il bus di sistema chiede al controller l’accesso alla periferica.
- Traduce i protocolli di comunicazione del bus di sistema in quelli del bus della periferica (traduce le richieste del sistema operativo))
- Esempio: un USB Controller converte i dati dal bus di sistema in un formato compatibile con il bus USB.
- Adapter/Device driver (autista → bus):
- Collega elettricamente due tipi di bus diversi.
- Normalmente collega il bus di memoria al bus della periferica.
- Ruolo del Bus di Sistema
Il bus di sistema è l’interfaccia che collega tutte le componenti hardware, come memoria, CPU e periferiche (precisamente tramite una rete lungo al quale fluiscono i dati).
SISTEMA I/O PROGRAMMATO (problema busy waiting CPU)
tipo di gestione delle operazioni I/O in cui l’informazione è totalmente gestita dalla CPU che però fa busy waiting
Come funziona
Un esempio tipico coinvolge un processo in spazio utente che necessita di utilizzare una periferica, come una stampante.
- Il processo lancia una System Call in cui trasferisce la richiesta al kernel, chiedendo che venga stampata la stringa
- Il kernel si occupa di inviare la stringa alla stampante, carattere per carattere
- Nell‘attesa del kernel, la CPU fa busy waiting per capire se la stampante è pronta per accettare il successivo (esegue il processo oper verificare se è pronto)
- va bene nei sistemi semplici ma INACCETTABILE in quelli più complessi, pk tiene occupata la CPU impedendola di eseguire nel frattempo, altri processi
SISTEMA I/O GESTITO DAGLI INTERRUPT (soluzione, CPU ottimizzata in I/O)
Gli interrupt eliminano il problema del busy waiting, pk quando il kernel lavora con la periferica, nel frattempo il processo è messo in stato di blocco. Quindi la CPU ritorna al processo quando è in ready e la periferica lancia un interrupt di terminata operazione.
SISTEMA I/O CON DIRECT MEMORY ACCESS: DMA (CPU usata al minimo in I/O)
L’I/O tramite DMA (Direct Memory Access) è nato per evitare che la CPU dovesse andarsi a prendere i dati dalla periferica. Questo meccanismo continua ad utilizzare gli interrupt, ma al loro arrivo i dati devono essere già in memoria.
Agenti Coinvolti
Nel processo di DMA partecipano quattro componenti principali:
- CPU: Fa la richiesta iniziale per l'operazione di I/O.
- Device Controller della periferica: Gestisce l'interazione diretta con la periferica.
- RAM: Destinazione o origine dei dati trasferiti.
- DMA controller: Hardware specializzato che coordina il trasferimento dei dati tra periferica e memoria, riducendo il lavoro della PCU
Procedura Operativa
- CPU - DMA
- Indirizzo di origine o destinazione dei dati in memoria.
- Quantità di dati da trasferire.
- Altri parametri
La CPU esegue il processo e quando riscontra un operazione I/O fornisce al DMA controller le seguenti informazioni:
- DMA - Controller della Periferica
Il DMA controller passa la richiesta al controller della periferica, indicando la posizione di memoria dove i dati dovranno essere depositati.
- Controller - destinatario (memoria o periferica)
- Modalità Burst: Il controller attende di ottenere il bus di sistema e, una volta acquisito, trasferisce tutti i dati in un’unica operazione
- PMB: la CPU però a cmq bisogno di comunicare con la RAM per questioni di efficienza e qualità del servizio. Quindi le architetture moderne includono un bus dedicato per collegare direttamente la CPU alla memoria, chiamato PMB (Primary Memory Bus). Questo bus, essendo elettricamente più corto, offre una maggiore capacità di trasferimento rispetto al bus di sistema.
- Modalità Cycle Stealing: Il controller sfrutta i momenti in cui il bus è libero per trasferire piccoli blocchi di dati. Questa modalità offre prestazioni inferiori rispetto alla modalità burst.
- Quando il bus di sistema è occupato con trasferimenti di dati tra periferica e memoria RAM, la CPU nn può lavorare
- bus dedicato unicamente per collegare la CPU alla memoria
- maggiore capacità di trasferimento rispetto al bus di sistema.
Quando la periferica completa l’operazione I/O, il controller scrive autonomamente i dati in memoria centrale, nella posizione indicata dal DMA controller.
Soluzione = PMB (Primary Memory Bus)
- Segnale di Completamento
- Una volta completato il trasferimento, il controller della periferica invia un segnale di completamento al DMA (non interrupt) al controller, indicando che l'operazione è stata eseguita
- Notifica alla CPU
Il DMA controller determina che l'intero trasferimento è terminato, invia un interrupt alla CPU per notificare che i dati sono stati trasferiti correttamente nella posizione di memoria richiesta.
INTERRUPT CONTROLLER
Gli interrupt non arrivano direttamente alla CPU, ma sono gestiti da un componente intermedio chiamato interrupt controller, che media la comunicazione e garantisce un funzionamento ordinato.
Ruolo dell'Interrupt Controller
- Evita sovrapposizioni: Assicura che non ci siano conflitti tra interrupt generati da periferiche diverse.
- Gestione dei ritardi: Se la CPU non è momentaneamente disponibile a gestire un interrupt, l'interrupt controller lo conserva in un piccolo buffer e lo inoltra con un lieve ritardo (nell'ordine dei microsecondi).
- Prevenzione della perdita di interrupt: Garantisce che la CPU riceva correttamente ogni interrupt, grazie alla gestione degli acknowledgement (conferme di ricezione).
Priorità degli Interrupt
L'interrupt controller può anche gestire priorità tra diversi interrupt, assicurando che quelli più critici vengano gestiti per primi. Ad esempio:
- L'interrupt del clock, fondamentale per il time-sharing e la gestione temporale del sistema, ha sempre una priorità più alta rispetto a quello di una periferica meno urgente, come una stampante che ha terminato un lavoro.
Differenza tra Interrupt e Trap
Una domanda frequente riguarda la differenza tra interrupt e trap:
- Interrupt: È asincrono, cioè può arrivare in qualsiasi momento, indipendentemente dallo stato della CPU. Ad esempio, una periferica può inviare un interrupt alla CPU per segnalare la disponibilità di dati.
- Trap: È sincrona, cioè si verifica in relazione agli stati interni della CPU e al flusso di esecuzione delle istruzioni. Ad esempio:
- Una divisione per zero genera una trap durante la fase di execute, perché è strettamente legata all'esecuzione del microcodice.
- Un page fault (mancanza di pagina in memoria) può avvenire nelle fasi di fetch o decode, ma mai a metà di queste fasi.
(In questo caso l’interrupt è lanciato quando le risorse sono già allocate)
DIFFERENZA DI COMPLESSITA GESTIONE INTERRUPT: Architetture legacy e con Pipeline
Gestire gli interrupt nelle moderne architetture con pipeline è molto più complesso rispetto alle architetture legacy, a causa della presenza di più istruzioni in fase di esecuzione parallela. Questo comporta sfide significative, specialmente nella gestione dello stato del processore.
Interrupt nelle Architetture Legacy
Nelle architetture più semplici, con un unico flusso sequenziale di fetch-decode-execute:
- L’interrupt poteva essere gestito facilmente pk esegue un istruzione per volta
- La CPU aveva uno stato ben definito, rappresentato da
- Program Counter (PC)
- set di registri, che potevano essere salvati nel Process Control Block (PCB) per riprendere l’esecuzione dopo la gestione dell’interrupt
Interrupt nelle Architetture Pipeline
Nelle moderne architetture con pipeline, il flusso di istruzioni è suddiviso in più fasi che si occupano ciascuno di una istruzione (in contemporanea, come una catena di montaggio):
- Le istruzioni di un singolo processo possono essere in stati differenti: pk appunto eseguiti contemporaneamente
Quando arriva un interrupt in questo contesto:
- Non esiste un stato unico e preciso per il processo, da salvare nel PCB.
Soluzioni Utilizzate
- Buffer di Stato Avanzati: le CPU moderne utilizzano buffer per memorizzare lo stato intermedio di ogni istruzione
- Se ogni interruzione causasse immediatamente il salvataggio dello stato nel PCB, ci sarebbe un enorme overhead per il sistema operativo.
- Commit: retrocedo al punto di commit, ovvero la prima istruzione che mi garantisce il salvataggio coerente dello stato della CPU (annullo l’esecuzione di alcune di istruzioni)
- Priorità degli Interrupt: Alcuni interrupt particolarmente critici (es. interrupt di clock) possono forzare la pipeline a svuotarsi immediatamente, mentre altri vengono gestiti con maggiore flessibilità.
INTERRUPT PRECISO
Un interrupt preciso è un tipo di interrupt che garantisce che, al momento della sua gestione, la CPU si trovi in uno stato ben definito e coerente, alla ripresa di un processo
4 Condizioni per un Interrupt Preciso
- Program Counter Determinato:
rappresenta esattamente l’istruzione successiva da eseguire.
- Istruzione Puntata dal Program Counter in Stato Determinato:
senza ambiguità o effetti parziali
- Istruzioni Precedenti Completate:
Tutte le istruzioni prima del valore indicato dal Program Counter sono state eseguite completamente
- Nessuna microistruzione successiva al Program Counter è stata eseguita
I/O SOFTWARE: 5 caratteristiche
Indipendenza dal Dispositivo
Il software di I/O deve essere indipendente dal tipo di periferica, quindi compatibile con tutte le periferiche connesse all’elaboratore
Nomenclatura Uniforme
Una nomenclatura uniforme per le operazioni di I/O
- Nei sistemi come Unix, tutte le operazioni di I/O sono gestite come se si trattasse di operazioni su file. Ad esempio, si utilizzano le stesse funzioni (come
open,read,write,close) per interagire sia con file che con periferiche
- in aggiunta alle istruzioni per accedere allo spazio delle porte: qui
Gestione degli Errori
Il software di I/O deve includere un sistema per gestire gli errori in modo uniforme e indipendente dal dispositivo.
Software Sincrono e Asincrono
Il software di I/O deve supportare sia modalità sincrone (durante l’attesa, il processo rimane bloccato (non esegue altre operazioni) che asincrone (continua ad eseguire altre operazioni, senza aspettare il completamento immediato)
Utilizzo dei Buffer
- Questo meccanismo velocizza le operazioni di I/O pk nn si fa accesso alle periferiche per consegnare i dati ma ai buffer
MAPPATURA BUFFER
In tanto i buffer devono avere una posizione precisa in memoria, cosicché accedendo al valore di questi indirizzi la CPU sa dove scrivere i dati
Modalità di mappatura
- Spazio di indirizzamento separato ("spazio delle porte")
- Si trova nell’hardware del processore ed è accessibile solo attraverso istruzioni specifiche.
- La CPU utilizza istruzioni specializzate (come
INeOUT+ tipo di operazione) per leggere e scrivere dati direttamente nei registri o buffer delle periferiche.
- Mappatura in RAM: insieme alla richiesta di operazione I/O
Caratteristica | Spazio delle Porte | Mappatura nel Processo |
Tipo di Indirizzo | Indirizzo fisico diretto | Indirizzo virtuale nello spazio del processo → da tradurre |
Traduzione MMU | Non necessaria | Necessaria |
Istruzioni CPU | Istruzioni specializzate ( IN, OUT) | Istruzioni standard ( MOV, LOAD) |
Separazione dalla Memoria | Separato dallo spazio della memoria (pk inserito nello spazio delle porte) | Integrato nello spazio della memoria, pk interno al processo quindi sta neil soliti spazi di memoria (RAM, disco…) |
Efficienza | Veloce, ma richiede istruzioni dedicate | Più flessibile, ma dipende dalla MMU |
- Configurazione ibrida
Nei sistemi moderni, le periferiche possono essere accessibili sia tramite lo spazio di indirizzamento del processo sia tramite lo spazio delle porte. Questa combinazione offre maggiore flessibilità.
TEMPORIZZAZIONE BUFFERS
Funzionamento Generale del Buffering
Quando un processo utente deve inviare o ricevere dati attraverso una periferica:
- Buffer del Kernel
- Il processo passa i dati al buffer del kernel
- Buffer delle Periferiche
- il kernel deposita i dati per il controller della periferica
- Le periferiche sono dotate di due buffer distinti:
- Buffer in ingresso: Per i dati ricevuti (dal kernel)
- Buffer in uscita: Per i dati da inviare (in RAM)
Problematiche del Buffering = temporizzazione
- Se i buffer di sistema si riempiono, non è possibile accodare ulteriori dati. Questo porta alla perdita di informazioni
- Perdita del modello produttore-consumatore: In alcuni casi, come con un modem, il sistema non riesce a mantenere un flusso regolare di dati tra produttore e consumatore, causando perdita di informazioni
- Questo è meno problematico con dispositivi come i dischi, che hanno tempi di risposta più prevedibili → streaming problematico
SOLUZIONE
- Utilizzo di Buffer Multipli tra le vaire fasi di trasfermento dei dati
- Attesa Conferma di invio: Quando il kernel trasferisce i dati al controller della scheda di rete, il controller gestisce l'invio e notifica il completamento tramite un interrupt. Questo garantisce che il kernel non invii dati oltre la capacità del buffer del controller.
- Attesa Conferma di ricezione: Quando la scheda di rete riceve dati dalla rete, genera un interrupt per notificare il kernel. Questo evita che il kernel tenti di leggere dati non ancora disponibili (busy waiting)
- la system call avvisa quando il kernel può prelevare i dati
DIFFERENZA TRA DEVICE DRIVER E DECIVE CONTROLLER
- DEVICE DRIVER (software)
- Traduzione dei comandi: converte le richieste di alto livello in istruzioni/comandi comprensibili per la periferica
- utilizza un buffer per ottimizzare il trasferimento dei dati tra il sistema operativo e la periferica
- DEVICE CONTROLLER (hardware) = componente fisica che collega il bus dati del sistema con il dati della periferica collegata al computer