Riassunto gerarchico delle nozioni del corso 2003-2004 di
Sistemi Operativi del Prof. Francesco Aymerich - Università degli
Studi di Cagliari, Facoltà di Scienze Matematiche Fisiche Naturali,
Dipartimento di Matematica ed Informatica, Corso di Laurea in
Informatica
- considerazioni generali su input e output
- una delle funzioni principali di un sistema operativo è il controllo di tutti i dispositivi di I/O del computer.
- il sistema operativo deve
- comandare i dispositivi, intercettare le interruzioni e gestire gli errori.
- fornire un'interfaccia semplice e di facile uso tra i
dispositivi e il resto del sistema.
- per quanto possibile, l'interfaccia dovrebbe essere la stessa per tutti i dispositivi (indipendenza dal dispositivo).
- il codice di I/O rappresenta una frazione significativa di tutto il sistema operativo
- le periferiche possono differenziarsi per uno o più dei
seguenti aspetti
- 1) velocità
- vi può essere una differenza di svariati ordini di grandezza
tra le velocità di trasferimento dei dati di differenti
periferiche.
- un disco magnetico, ad esempio, può essere in grado di trasferire 106 caratteri al secondo, contrariamente alla velocità della tastiera di un terminale pari a solo pochi caratteri al secondo (in funzione della bravura del dattilografo, ovviamente).
- vi può essere una differenza di svariati ordini di grandezza
tra le velocità di trasferimento dei dati di differenti
periferiche.
- 2) unità di trasferimento
- in base alla periferica utilizzata, i dati si possono trasferire in unità di informazione corrispondenti a caratteri, word, byte, blocchi o record.
- 3) rappresentazione dei dati
- un singolo dato può essere codificato in modi diversi e su
diversi supporti di informazione.
- anche entro un singolo supporto, quale un nastro magnetico, si possono usare codici differenti. l
- le periferiche differiscono per il tipo di operazione che sono
in grado di svolgere:
- un esempio è dato dall'ovvia distinzione tra input ed output; un altro consiste nella capacità di riavvolgere il nastro magnetico, ma non la carta di una stampante parallela.
- un singolo dato può essere codificato in modi diversi e su
diversi supporti di informazione.
- 5) situazioni d'errore
- il mancato completamento di un trasferimento dati può essere determinato da varie cause, quali un errore di parità, l'inceppamento di schede o un errore in una somma di controllo, a seconda della periferica in uso.
- 1) velocità
- è chiaramente difficile gestire in modo uniforme le diversità esemplificate in precedenza
- dispositivi di I/O
- possono essere suddivisi in due categorie:
- 1) dispositivi a blocchi
- registrano le informazioni in blocchi di dimensioni fisse, ognuno con un suo indirizzo.
- le dimensioni del blocco vanno di solito da 512 a 32768 byte.
- la proprietà fondamentale di un dispositivo a blocchi è che
ogni blocco può essere letto o scritto indipendentemente dagli
altri.
- i dischi sono i dispositivi a blocchi più comuni.
- 2) dispositivi a caratteri
- forniscono o accettano una sequenza di caratteri senza curarsi della strutturazione a blocchi.
- un dispositivo di questo tipo non è indirizzabile e non ha
alcuna operazione di posizionamento (seek).
- le stampanti, le periferiche di rete, i mouse nonché molti altri dispositivi che non somigliano affatto ai dischi possono essere visti come dispositivi a caratteri
- 1) dispositivi a blocchi
- il confine tra i dispositivi indirizzabili a blocchi e quelli
che non lo sono non è così ben definito.
- tutti sono d'accordo nel considerare il disco un dispositivo indirizzabile a blocchi perché, indipendentemente dalla posizione corrente del braccio, è sempre possibile spostarsi su un altro cilindro e attendere quindi che il blocco desiderato passi sotto la testina.
- consideriamo ora un lettore di nastri 8 mm o DAT utilizzato per
effettuare il backup del disco.
- il nastro contiene in genere blocchi di dimensione fissa.
- se si comanda al lettore di nastri la lettura del blocco N, esso può riavvolgere il nastro e andare avanti fino a che non arriva al blocco N.
- quest'operazione è analoga a una ricerca sul disco, eccetto che
il tempo necessario per completarla è di gran lunga superiore
- inoltre, non è detto che sia possibile riscrivere un blocco nel mezzo del nastro.
- anche se fosse possibile utilizzare i nastri come dispositivi
con accesso casuale al blocco, questa rappresentazione sarebbe in
qualche modo una forzatura:
- le unità a nastro non vengono normalmente usate in questo modo
- controllore di dispositivo (adapter)
- è la parte elettronica di un dispositivo, in contrapposizione
alla parte meccanica (se presente) che costituisce il dispositivo
vero e proprio
- sui personal computer prende spesso la forma di una scheda a circuito stampato che può essere inserita in una delle connessioni presenti sulla parentboard del computer
- la scheda del controllore ospita di solito un connettore, nel
quale si può inserire un cavo che porta al dispositivo stesso.
- molti controllori possono gestire due, quattro o perfino otto dispositivi identici
- se l'interfaccia tra il controllore e il dispositivo è
un'interfaccia standard, sia esso uno standard ufficiale come ANSI,
IEEE o ISO o uno standard di fatto, le ditte possono costruire
controllori o dispositivi che rispettino tale interfaccia.
- come accade nel caso delle interfacce per controllori IDE (Integrated Drive Electronics) o SCSI (Small Computer System Interface).
- menzioniamo questa differenza tra controllore e dispositivo in quanto il sistema operativo ha quasi sempre a che fare con il controllore e non con il dispositivo.
- molti piccoli computer usano il modello a bus singolo per
mettere in comunicazione la CPU e i controllori.
- i grandi mainframe utilizzano spesso un modello diverso, con bus multipli e computer specializzati per l'I/O chiamati I/O channels (canali di I/O), che risparmiano alla CPU principale una parte del carico computazionale
- l'interfaccia tra il controllore e il dispositivo è spesso di
livello molto basso.
- un disco, ad esempio, può essere strutturato con un formato di
16 settori di 512 byte per traccia.
- ciò che in realtà esce dal dispositivo è una sequenza seriale di bit che inizia con un preambolo, prosegue con i 4096 bit per settore e contiene infine un codice di correzione d'errore o checksum (ECC o Error Correcting Code).
- il preambolo viene scritto quando viene definito il formato del disco e contiene l'indice di cilindro e di settore, la dimensione del settore e dati analoghi, insieme alle informazioni di sincronizzazione
- il compito del controllore è di convertire la sequenza seriale di bit in un blocco di byte ed effettuare un'eventuale correzione d'errore.
- di solito il blocco dei byte viene inizialmente assemblato, un
bit alla volta, in un buffer all'interno del controllore.
- dopo che il suo checksum è stato controllato e il blocco è stato dichiarato libero da errori, può essere copiato nella memoria principale
- un controllore video è un dispositivo seriale a bit
- legge dalla memoria i byte contenenti i caratteri da mostrare e genera i segnali usati per modulare il raggio del tubo catodico affinché scriva sullo schermo.
- genera anche i segnali che comandano il ritracciamento orizzontale del raggio catodico dopo che la scansione di una riga è terminata, e i segnali per effettuare il ritracciamento verticale dopo che l'intero quadro è stato scandito.
- se non fosse per il controllore dello schermo, il programmatore del sistema operativo dovrebbe programmare esplicitamente la scansione analogica dello schermo
- il sistema operativo inizializza il controllore con alcuni parametri, come il numero di caratteri per linea e il numero di linee contenute nello schermo, e lascia che il controllore si prenda cura di controllare esplicitamente il raggio di elettroni
- un disco, ad esempio, può essere strutturato con un formato di
16 settori di 512 byte per traccia.
- I/O mappato in memoria (memory mapped I/O)
- ogni controllore usa un certo numero di registri per comunicare con la CPU
- i registri possono far parte del normale spazio di
indirizzamento della memoria
- il 680x0, ad esempio, usa questo metodo
- altri computer usano uno spazio di indirizzamento speciale per
l'I/O
- allocano a ogni controllore una determinata porzione di tale spazio.
- l'assegnamento degli indirizzi di I/O ai dispositivi viene fatto mediante la logica di decodifica degli indirizzi del bus, compresa all'interno del controllore
- alcuni produttori dei cosiddetti PC compatibili IBM usano indirizzi diversi da quelli utilizzati da IBM
- in aggiunta alle porte di I/O, molti controllori utilizzano le
interruzioni per far sapere alla CPU quando sono pronti per la
lettura o la scrittura dei propri registri.
- un'interruzione è, in primo luogo, un evento elettrico, una
linea hardware di richiesta di interruzione (IRQ) corrispondente a
un ingresso fisico nel circuito controllore delle interruzioni.
- il numero di tali ingressi è limitato;
- i PC della categoria Pentium ne hanno a disposizione solo 15 per tutti i dispositivi di I/O.
- il numero di tali ingressi è limitato;
- alcuni controllori sono integrati fisicamente nella parentboard
di sistema,
- come ad esempio il controllore della tastiera di un PC IBM.
- nel caso il controllore di un dispositivo sia invece inserito nel backplane, si possono talvolta usare interruttori o ponticelli per selezionare quale linea di IRQ sarà utilizzata dal dispositivo e per evitare conflitti (benché in alcune schede, come nelle Plug & PIay, gli IRQ possano essere impostati via software).
- il controllore delle interruzioni trasforma ogni ingresso IRQ in un vettore di interruzione che individua il corrispondente software di servizio.
- un'interruzione è, in primo luogo, un evento elettrico, una
linea hardware di richiesta di interruzione (IRQ) corrispondente a
un ingresso fisico nel circuito controllore delle interruzioni.
- esempio PC/IBM (Controllore I/O, Indirizzo I/O, IRQ, vettore
d'Interrupt)
- clock, 040-043, 0, 8
- tastiera, 060-063, 1, 9
- harddisk, 1f0-1f7, 14, 11
- rs232 secondaria, 2f8-2ff, 3, 11
- stampante, 378-37f, 7, 15
- floppy disk, 3f0-3f7, 6, 14
- rs232 primaria, 3f8-3ff, 4, 12
- il sistema operativo effettua l'I/O scrivendo comandi nei
registri del controllore.
- il controllore dei floppy disk del PC IBM, ad esempio, accetta
15 comandi diversi come READ, WRITE, SEEK, FORMAT e RECALIBRATE.
- molti dì questi comandi hanno dei parametri che vengono a loro volta caricati nei registri del controllore.
- quando un comando è stato accettato, la CPU lascia che il controllore faccia il suo lavoro e passa a occuparsi d'altro.
- quando il comando è stato completato, il controllore genera un'interruzione per permettere al sistema operativo di riprendere il controllo della CPU e controllare i risultati dell'operazione.
- la CPU ottiene i risultati e lo stato del dispositivo leggendo
uno o più byte di informazione dai registri del controllore.
- REGISTRI - FUNZIONE IN LETTURA - FUNZIONE IN SCRITTURA
- 0 - dati - dati
- 1 - errore - precompensazione in lettura
- 2 - numero di settori - numero di settori
- 3 - indice di settore (0-7) - indice di settore (0-7)
- 4 - cilindro (parte inferiore, 8-15) - cilindro (parte inferiore, 8-15)
- 5 - cilindro (parte superiore, 16-23) - cilindro (parte superiore, 16-23)
- 6 - seleziona drive/testina (24-27) - seleziona drive/testina (24-27)
- 7 - stato - comando
- i numeri tra parentesi sono i bit dell'indirizzo logico di blocco selezionato da ogni registro in modalità LBA
- 7 - 1
- 6 - LBA
- 5 - 1
- 4 - D
- 3 - HS3
- 2 - HS2
- 1 - HS1
- 0 - HS0
- Valori:
- LBA = 0 Modalità cilindro/testina/settore, 1 Modalità di indirizzamento Blocco Logico
- D = 0 drive master, 1 drive slave
- i quattro bit HSn indicano: in modalità C/T/S la testina, in modalità Blocco Logico i bit 24-27 selezionano il blocco
- il controllore dei floppy disk del PC IBM, ad esempio, accetta
15 comandi diversi come READ, WRITE, SEEK, FORMAT e RECALIBRATE.
- è la parte elettronica di un dispositivo, in contrapposizione
alla parte meccanica (se presente) che costituisce il dispositivo
vero e proprio
- possono essere suddivisi in due categorie:
- accesso diretto in memoria - DMA
- molti controllori, specialmente quelli per i dispositivi orientati al blocco, supportano l'accesso diretto in memoria o DMA (Direct Memory Access).
- lettura da disco senza DMA:
- il controllore legge il blocco (uno o più settori) dal dispositivo in modo seriale, bit a bit, fino a che l'intero blocco non è nel suo buffer interno
- il controllore calcola il checksum per verificare che non vi siano stati errori in lettura.
- il controllore genera un'interruzione.
- quando il sistema operativo va in esecuzione, esso può leggere
il blocco di disco dal buffer del controllore, un byte o una parola
alla volta, eseguendo un ciclo in cui a ogni iterazione un byte o
una parola vengono letti da un registro del controllore del
dispositivo e immagazzinati in memoria
- programmare un ciclo sulla CPU che legga uno alla volta i byte dal controllore significa sprecare tempo di CPU
- lettura da disco col DMA:
- la CPU fornisce al controllore l'indirizzo sul disco del blocco
e due ulteriori informazioni:
- l'indirizzo di memoria in cui mettere il blocco
- il numero di byte da trasferire
- dopo aver letto l'intero blocco dal dispositivo nel suo buffer e verificato il checksum, il controllore copia il primo byte o la prima parola nella memoria principale, all'indirizzo specificato dall'indirizzo di memoria interno al DMA.
- quindi incrementa l'indirizzo nel DMA e decrementa il contatore del DMA del numero di byte appena trasferiti.
- questo procedimento viene ripetuto fino a che il contatore del DMA diventa zero.
- a questo punto il controllore genera un'interruzione.
- quando il sistema operativo prende il controllo della CPU, non ha più bisogno di copiare il blocco in memoria: esso è stato già trasferito.
- la CPU fornisce al controllore l'indirizzo sul disco del blocco
e due ulteriori informazioni:
- motivi che rendono necessaria la presenza di un buffer interno
nel controllore:
- una volta che un trasferimento da disco è stato avviato, i bit arrivano dal disco a un ritmo costante, che il controllore sia pronto a riceverli o no.
- se il controllore cerca di scrivere i dati direttamente in
memoria, deve passare attraverso il bus di sistema ogni volta che
intende trasferire una parola.
- se il bus è occupato perché utilizzato da qualche altro dispositivo, il controllore è costretto ad attendere.
- se la successiva parola arriva dal disco prima che la
precedente sia stata trasferita, il controllore dovrebbe
memorizzarla da qualche parte.
- se il bus fosse molto occupato, il controllore finirebbe per memorizzare un gran numero di parole e dovrebbe allo stesso tempo svolgere un oneroso lavoro di gestione.
- quando si memorizza il blocco in un buffer interno, il buffer
non viene richiesto fino a che non si avvia l'accesso in DMA; di
conseguenza il progetto del controllore è più semplice, dato che i
trasferimenti dal DMA alla memoria non hanno vincoli temporali
- alcuni vecchi controllori andavano in effetti a scrivere direttamente in memoria e si limitavano a gestire un piccolo buffer interno, ma quando il bus risultava molto occupato, un trasferimento si poteva concludere con un errore di overrun
- influenza sulle prestazioni
- mentre i dati vengono trasferiti dal controllore alla memoria, sotto il controllo della CPU del controllore, il settore seguente passa sotto la testina e i bit arrivano al controllore.
- i controllori più semplici non riescono a gestire l'ingresso e l'uscita simultanea dei dati, così, mentre ha luogo un trasferimento in memoria, il settore che passa sotto la testina viene perduto.
- come risultato, il controllore sarà capace di leggere solo un blocco ogni due.
- la lettura di un'intera traccia comporterà due rotazioni, una per i blocchi pari e una per i blocchi dispari.
- se il tempo necessario a trasferire un blocco dal controllore
alla memoria attraverso il bus risultasse maggiore del tempo
necessario a leggere un blocco dal disco, potrebbe essere
necessario leggere un blocco e saltarne quindi due (o più).
- la tecnica che prevede di saltare alcuni blocchi per dare tempo al controllore di trasferire i dati in memoria viene chiamata interleaving
- non tutti i computer usano il DMA.
- la CPU è spesso molto più veloce del controllore del DMA e può
svolgere il suo lavoro molto più velocemente (quando il fattore
limitante non è la velocità del dispositivo di I/O).
- se non ha nient'altro da fare, non ha senso che la CPU (veloce) attenda che il controllore del DMA (lento) finisca.
- eliminando il controllore del DMA e lasciando che la CPU faccia tutto il lavoro in software si risparmiano soldi.
- la CPU è spesso molto più veloce del controllore del DMA e può
svolgere il suo lavoro molto più velocemente (quando il fattore
limitante non è la velocità del dispositivo di I/O).
- hardware dei dischi
- geometria dei dischi
- i dischi reali sono organizzati in cilindri, ognuno contenente
tante tracce quante sono le testine allineate in verticale.
- le tracce sono divise in settori, e il numero dei settori posizionati intorno alla circonferenza è tipicamente compreso tra 8 e 32 per i floppy disk, mentre arriva a diverse centinaia su alcuni hard disk.
- i modelli più semplici hanno lo stesso numero di settori su
ogni traccia.
- tutti i settori contengono lo stesso numero di byte
- i settori più vicini al bordo esterno del disco saranno fisicamente più lunghi di quelli vicini all'asse.
- il tempo necessario a leggere o scrivere ogni settore sarà lo stesso.
- tutti i settori contengono lo stesso numero di byte
- la densità dei dati è ovviamente più alta sui cilindri più
interni
- alcuni modelli di disco richiedono un cambiamento nella corrente di comando per le testine di lettura-scrittura quando si trovano a operare sulle tracce più interne
- questa geometria viene gestita dall'hardware del controllore del disco e non è visibile all'utente (o al realizzatore di un sistema operativo)
- i dischi reali sono organizzati in cilindri, ognuno contenente
tante tracce quante sono le testine allineate in verticale.
- la differenza nella densità dei dati tra le tracce interne ed
esterne comporta un sacrificio in termini di capacità
- esistono sistemi di gestione più sofisticati:
- sono stati realizzati alcuni modelli di floppy disk che ruotano
a velocità più alte quando le testine sono sopra le tracce esterne.
- questo metodo consente di ottenere più settori nelle tracce esterne, aumentando la capacità del disco.
- i moderni hard disk di grandi capacità contengono più settori
nelle tracce esterne rispetto alle tracce interne.
- sono di questo tipo i drive IDE (Integrated Drive Electronics)
e le sofisticate elaborazioni effettuate dall'elettronica interna
al drive ne mascherano i dettagli realizzativi.
- essi appaiono al sistema operativo come se avessero una geometria semplice con lo stesso numero di settori per ogni traccia
- sono di questo tipo i drive IDE (Integrated Drive Electronics)
e le sofisticate elaborazioni effettuate dall'elettronica interna
al drive ne mascherano i dettagli realizzativi.
- sono stati realizzati alcuni modelli di floppy disk che ruotano
a velocità più alte quando le testine sono sopra le tracce esterne.
- esistono sistemi di gestione più sofisticati:
- l'elemento principale della scheda del controllore inserita nel
backplane del computer è un circuito integrato specializzato, un
piccolo microcomputer
- la circuiteria della scheda controllore di un hard disk può essere più semplice di quella di un floppy disk, ma questo accade perché i drive degli hard disk hanno un potente controllore elettronico al loro interno
- overlapped seeks
- è la possibilità per il controllore di effettuare posizionamenti (seek) su due o più drive allo stesso tempo
- molti controllori possono anche leggere o scrivere su un drive
mentre effettuano posizionamenti su uno o più altri drive
- un controllore di floppy disk non può leggere da o scrivere su due drive nello stesso istante (le letture e le scritture richiedono che il controllore sposti i bit in intervalli di pochi microsecondi, quindi ogni trasferimento usa la maggior parte del suo potere computazionale).
- la situazione è diversa per gli hard disk con controllori
integrati, e in un sistema con più drive di questo tipo i
controllori possono operare simultaneamente, almeno per quel che
riguarda i trasferimenti tra il disco e la memoria di buffer del
controllore
- In ogni caso, è possibile un solo trasferimento alla volta tra il controllore e la memoria di sistema.
- la possibilità di effettuare due o più operazioni allo stesso tempo può ridurre in modo considerevole il tempo medio di accesso
- quando si leggono le specifiche dei moderni hard disk bisogna fare attenzione al fatto che la geometria specificata e usata dal software del driver può essere differente dal formato fisico.
- l'hard disk, WD-AC2 540, descritto in seguito è ad esempio
specificato con "parametri di configurazione raccomandati"
- 1048 cilindri
- 16 testine
- 63 settori per traccia
- l'elettronica del controllore montata sul disco converte i
parametri logici di testina e settore forniti dal sistema operativo
in quelli fisici utilizzati dal disco.
- questo è un ulteriore esempio di un compromesso studiato per
mantenere la compatibilità con i sistemi precedenti
- infatti nel vecchio firmware i progettisti del PC IBM originario riservarono nella ROM del BIOS un campo dì soli 6 bit per il contatore dì settore
- un disco che abbia più di 63 settori fisici per traccia deve funzionare con un insieme artificiale di parametri logici di disco.
- in questo caso, le specifiche del costruttore indicano che ci
sono in realtà quattro testine, e pertanto sembrerebbe che ci siano
252 settori per traccia
- questa è però un'ulteriore semplificazione, perché i dischi di questo tipo contengono più settori nelle tracce esterne di quanti ne abbiano nelle tracce interne.
- il disco descritto ha in effetti quattro testine, ma contiene
in realtà un po' più di 3000 cilindri.
- i cilindri sono raggruppati in una dozzina di zone che hanno da un minimo di 57 settori per traccia nelle zone più interne a un massimo di 105 nei cilindri più esterni.
- questi numeri non si trovano nelle specifiche del disco e le traduzioni effettuate dall'elettronica del drive consentono di fare a meno di questi dettagli
- questo è un ulteriore esempio di un compromesso studiato per
mantenere la compatibilità con i sistemi precedenti
- geometria dei dischi
- software del disco
- il tempo necessario a scrivere (o leggere) un blocco di disco è
determinato da:
- 1) tempo di posizionamento (seek)
- tempo necessario a spostare il braccio che sostiene la testina sul cilindro giusto
- nella maggior parte dei casi è l'operazione più lenta per cui ridurre il tempo di seek contribuisce a migliorare notevolmente le prestazioni
- 2) ritardo di rotazione
- tempo necessario affinchè il settore richiesto, ruotando, giunga sotto la testina
- 3) tempo di trasferimento dati
- 1) tempo di posizionamento (seek)
- mentre un disco effettua un posizionamento è probabile che
vengano generate altre richieste di operazioni sul disco
- molti driver di dischi mantengono una tabella, indirizzata dal numero di cilindro, i cui elementi puntano a liste concatenate contenenti le richieste pendenti per ogni cilindro
- algoritmi di scheduling delle richieste
- First Come First Served - FCFS
- il disco accetta i comandi uno alla volta e li esegue in ordine di pervenimento
- con questo algoritmo non si può fare niente per migliorare le prestazioni
- esempio di funzionamento
- la testina si trova sul cilindro 11 quando arrivano nuove richieste per i cilindri 1, 36, 16, 34, 9, 12
- applicando l'algoritmo il braccio si sposta nella seguente
maniera:
- 11 -> 1, movimento di 10 cilindri
- 1 -> 36, movimento di 35 cilindri
- 36 -> 16, movimento di 20 cilindri
- 16 -> 34, movimento di 18 cilindri
- 34 -> 9, movimento di 25 cilindri
- 9 -> 12, movimento di 3 cilindri
- la testina si è spostata complessivamente per 111 cilindri
- Shortest Seek First - SSF
- si esegue per prima la richiesta più vicina al cilindro dov'è
posizionata la testina attualmente
- ossia scegliendo tra più cilindri si sceglie di accontentare per prima la richiesta al cilindro più vicino rispetto a quello attuale
- consente di minimizzare gli spostamenti della testina
- esempio di funzionamento
- la testina si trova sul cilindro 11 quando arrivano nuove richieste per i cilindri 1, 36, 16, 34, 9, 12
- applicando l'algoritmo il braccio si sposta nella seguente
maniera:
- 11 -> 12, movimento di 1 cilindri
- 12 -> 9, movimento di 3 cilindri
- 9 -> 16, movimento di 7 cilindri
- 16 -> 1, movimento di 15 cilindri
- 1 -> 34, movimento di 33 cilindri
- 34 -> 36, movimento di 2 cilindri
- la testina si è spostata complessivamente per 61 cilindri
- il maggiore difetto di questa tecnica è relativo al fatto che
per un uso pesante del disco la testina oscillerà mediamente sui
cilindri centrali, offrendo uno scarso servizio a quelli molto
interni o molto esterni
- gli obiettivi di tempo di risposta minimo ed equità sono in questo caso in conflitto
- si esegue per prima la richiesta più vicina al cilindro dov'è
posizionata la testina attualmente
- algoritmo dell'ascensore
- viene utilizzato nello scheduling delle richieste degli ascensori
- riesce a conciliare l'equità del servizio con l'efficienza
- richiede al software di mantenere un bit di informazione supplementare, quello relativo alla direzione: UP o DOWN
- quando una richiesta è stata soddisfatta, il disco (o
l'ascensore) controlla il bit di direzione
- se vale UP il disco soddisfa la prossima richiesta pendente
associata al cilindro più alto in attesa
- se non vi sono richieste su cilindri più alti il bit di direzione viene invertito, posto in DOWN
- se vale DOWN il disco soddisfa la prossima richiesta pendente
associata al cilindro più basso in attesa
- se non vi sono richieste su cilindri più alti il bit di direzione viene invertito, posto in UP
- se vale UP il disco soddisfa la prossima richiesta pendente
associata al cilindro più alto in attesa
- funzionamento
- la testina si trova sul cilindro 11 quando arrivano nuove richieste per i cilindri 1, 36, 16, 34, 9, 12, il bit di direzione è UP
- applicando l'algoritmo il braccio si sposta nella seguente
maniera:
- 11 -> 12, movimento di 1 cilindri
- 12 -> 16, movimento di 4 cilindri
- 16 -> 34, movimento di 18 cilindri
- 34 -> 36, movimento di 2 cilindri
- sono finite le richieste relative a cilindri verso l'altro e il bit di direzione viene invertito, posto in DOWN
- 36 -> 9, movimento di 27 cilindri
- 9 -> 1, movimento di 8 cilindri
- la testina si è spostata complessivamente per 60 cilindri
- mediamente l'algoritmo dell'ascensore si comporta peggio
dell'algoritmo SSF
- anche se in questo caso si comporta leggermente meglio
- proprietà dell'algoritmo
- dato un qualsiasi insieme di richieste, la quantità massima di cilindri di cui deve essere spostato il braccio per servire le richieste è fissa, pari al doppio del numero di cilindri
- algoritmo dell'ascensore modificato (Teory 1972)
- si esamina il disco sempre nella stessa direzione
- non è più necessario il bit di direzione
- quando è stata soddisfatta la richiesta pendente relativa al cilindro più alto la testina si sposta sul cilindro più piccolo per il quale è presente una richiesta e continua a soddisfare le richieste verso l'alto
- funzionamento
- la testina si trova sul cilindro 11 quando arrivano nuove richieste per i cilindri 1, 36, 16, 34, 9, 12
- applicando l'algoritmo il braccio si sposta nella seguente
maniera:
- 11 -> 12, movimento di 1 cilindri
- 12 -> 16, movimento di 4 cilindri
- 16 -> 34, movimento di 18 cilindri
- 34 -> 36, movimento di 2 cilindri
- 36 -> 1, movimento di 35 cilindri
- 1 -> 9, movimento di 8 cilindri
- la testina si è spostata complessivamente per 68 cilindri
- ha un comportamento mediamente migliore dell'algoritmo dell'ascensore
- si esamina il disco sempre nella stessa direzione
- First Come First Served - FCFS
- i moderni controllori di dischi danno la possibilità al
software di conoscere il numero del settore sul quale si trova la
testina
- nel caso vi siano più richieste in attesa sullo stesso cilindro
è possibile inviare una richiesta al disco per quel settore che per
primo passerà sotto la testina
- nel caso si abbiano più tracce per cilindro è possibile
effettuare richieste consecutive per tracce diverse senza alcun
degrado nelle prestazioni
- un controllore può selezionare in maniera istantanea qualsiasi testina
- nel caso si abbiano più tracce per cilindro è possibile
effettuare richieste consecutive per tracce diverse senza alcun
degrado nelle prestazioni
- se il tempo di posizionamento è molto minore del ritardo di
rotazione, occorre implementare le ottimizzazioni in maniera
differente
- le richieste pendenti vanno ordinate per settore
- appena il settore successivo sta per passare sotto la testina questa viene spostata sulla traccia giusta per effettuare la lettura o scrittura
- nel caso vi siano più richieste in attesa sullo stesso cilindro
è possibile inviare una richiesta al disco per quel settore che per
primo passerà sotto la testina
- i moderni dischi implementano una cache nel controllore
- attualmente le cache sono di alcuni MB: 2, 4 o 8 MB
- quando viene effettuata la lettura di un settore, viene letto
quel settore più la maggior parte della traccia che lo contiene
- in questa maniera si riesce ad ottimizzare le prestazioni relative a richieste consecutive sulla stessa traccia
- l'uso della cache è determinato dinamicamente dal controllore
del disco
- nella modalità più semplice è divisa in due parti , lettura e scrittura
- quando è più presente più di un disco per controllore è necessario mantenere una tabella delle richieste pendenti separata per ogni disco
- quando un drive è inattivo, si dovrebbe impostare una ricerca
per muovere il suo braccio verso il cilindro in cui esso sarà
successivamente richiesto
- (assumendo che il controllore consenta ricerche sovrapposte).
- quando il trasferimento corrente termina, si può effettuare un
controllo per verificare se uno dei drive sia posizionato sul
cilindro corretto.
- se uno o più lo sono, il prossimo trasferimento può essere iniziato su uno di questi.
- se nessuno è nel posto giusto, il driver dovrebbe richiedere una nuova ricerca sul dispositivo che ha appena completato un trasferimento e aspettare la successiva interruzione per vedere quale braccio arrivi per primo a destinazione
- gli algoritmi precedenti risultano validi a livello di sistema
operativo se la geometria del disco reale corrisponde alla
geometria del disco virtuale
- altrimenti il S.O. no può sapere quale cilindro sia il più vicino al cilindro n
- gli algoritmi precedenti risultano sempre validi se implementati all'interno del controllore del disco
- il tempo necessario a scrivere (o leggere) un blocco di disco è
determinato da:
- gestione degli errori
- dischi RAM
- in un qualsiasi istante è possibile leggere o scrivere un
qualsiasi blocco senza alcun movimento fisico
- non devono preoccuparsi delle ottimizzazioni legate ai ritardi di ricerca o di rotazione
- non presentano problematiche particolari in relazione agli errori, funzionano sempre
- in un qualsiasi istante è possibile leggere o scrivere un
qualsiasi blocco senza alcun movimento fisico
- dischi reali
- sono soggetti a una vasta gamma di errori, alcuni dei più
comuni sono:
- 1. errori di programmazione
- si verificano quando il driver chiede al controllore di ricercare un cilindro inesistente, leggere da un settore inesistente, usare una testina che non esiste o trasferire dati da o verso locazioni di memoria inesistenti.
- la maggior parte dei controllori verificano i parametri passati loro e si lamentano nel caso in cui non siano validi.
- in teoria, questi errori non dovrebbero mai accadere, ma cosa
deve fare il driver se il controllore indica che se ne è verificato
uno?
- per il nostro sistema operativo, la miglior soluzione è fermarsi e stampare un messaggio del tipo "Chiamate il programmatore", in modo che l'errore possa essere individuato e sistemato.
- per un prodotto software commerciale in uso su migliaia di computer, probabilmente la sola cosa da fare è terminare la richiesta corrente per il disco con un errore
- 2. errori di checksum transitori
- gli errori transitori di checksum sono provocati da granelli di polvere presenti nell'aria tra la testina e la superficie del disco.
- nella maggior parte dei casi questi errori possono essere
eliminati ripetendo l'operazione alcune volte.
- se l'errore persiste, il blocco deve essere marcato come difettoso (bad block) ed evitato.
- un modo per evitare di usare i blocchi difettosi consiste nello scrivere un programma molto speciale che prenda in ingresso una lista di blocchi difettosi e confezioni attentamente un file contenente tutti i blocchi difettosi.
- una volta che questo file è stato creato, l'allocatore del disco penserà che tali blocchi siano occupati e non li allocherà mai
- 3. errori di checksum permanenti (ad es. un blocco sul disco fisicamente danneggiato)
- 4. errori di ricerca (ad es. il braccio spostato al cilindro 6 ma arrivato al 7)
- 5. errori del controllore (ad es. il controllore si rifiuta di accettare comandi).
- 1. errori di programmazione
- il driver del disco ha il compito di gestire tutti questi errori nel miglior modo possibile.
- sono soggetti a una vasta gamma di errori, alcuni dei più
comuni sono:
- dischi RAM
- obiettivi di progetto ed implicazioni
- 1) indipendenza dal codice dei caratteri
- non è auspicabile che, per la stesura dei propri programmi, un utente debba disporre di conoscenze particolareggiate sui codici dei caratteri impiegati dalle varie periferiche.
- il sistema di I/O deve assumersi il compito di riconoscere i diversi codici, presentando ai programmi utente i dati in forma codificata
- 2) indipendenza dal tipo di periferica
- un programma dovrebbe essere indipendente dalla particolare
tipologia del modello di periferica a cui capita di essere
destinato (una specifica stampante o disco)
- assicura di evitare fallimenti di programmi dovuti semplicemente alla rottura di una determinata periferica o alla sua destinazione ad altro compito
- concede al sistema operativo la facoltà di assegnare una periferica di tipo idoneo a seconda delle disponibilità complessive presenti in un dato momento
- uniformità dello spazio dei nomi
- il nome di un file o di un dispositivo dovrebbe essere semplicemente una stringa o un intero e non dipendere in alcun modo dal dispositivo
- in UNIX, tutti i dischi possono essere integrati
arbitrariamente nella gerarchia del file system in modo che
l'utente non abbia bisogno di sapere a quale nome corrisponda un
determinato dispositivo
- tutti i file e i dispositivi sono indirizzati con un nome di percorso
- è auspicabile che i programmi siano indipendenti, per quanto
possibile, dal tipo di unità utilizzata per il loro I/O
- per esempio, ricevere dati provenienti da disco anziché da nastro magnetico
- il sistema operativo si deve occupare dei problemi che nascono dall'effettiva diversità di questi dispositivi e dal fatto che i dispositivi richiedono gestori (device driver) profondamente diversi per scrivere fisicamente i dati
- un programma dovrebbe essere indipendente dalla particolare
tipologia del modello di periferica a cui capita di essere
destinato (una specifica stampante o disco)
- 3) efficienza
- poiché tutte le operazioni di I/O in un sistema di calcolo si rivelano spesso delle "strozzature" che provocano un calo nelle prestazioni del sistema stesso, è auspicabile svolgerle il più possibile in modo efficiente
- 4) uniformità di gestione delle periferiche
- per favorire la semplicità e l'assenza d'errori è auspicabile
che tutte le periferiche siano gestite in maniera uniforme.
- all'atto pratico questo può risultare difficile
- per favorire la semplicità e l'assenza d'errori è auspicabile
che tutte le periferiche siano gestite in maniera uniforme.
- 5) gestione degli errori
- gli errori dovrebbero essere gestiti per quanto possibile in
prossimità dell'hardware
- se il controllore scopre un errore in lettura, dovrebbe cercare, se può, di correggerlo esso stesso.
- se non ne ha la possibilità, è il gestore del dispositivo che
deve allora prendersene cura, magari semplicemente ritentando la
lettura del blocco.
- si risolve così quando gli errori sono transitori. I livelli superiori dovrebbero essere informati del problema solo se i livelli inferiori non sono in grado di affrontarlo. In molti casi, il recupero da un errore può essere fatto in modo trasparente a basso livello senza che i livelli superiori ne vengano a conoscenza.
- gli errori dovrebbero essere gestiti per quanto possibile in
prossimità dell'hardware
- 6) sincronizzazione
- è importante distinguere tra trasferimenti sincroni (bloccanti) e asincroni (gestiti a interruzione).
- la maggior parte dell'I/O fisico è asincrono
- la CPU inizia il trasferimento e continua le sue elaborazioni fino a che non arriva un'interruzione.
- i programmi utente sono però molto più semplici da scrivere se
le operazioni di I/O sono bloccanti
- dopo un comando di lettura il programma viene automaticamente sospeso fino a che i dati non sono disponibili nel buffer
- il sistema operativo deve far sembrare sincrone (bloccanti) ai programmi utente le operazioni che in realtà sono guidate dalle interruzioni, cioè asincrone.
- 7) condivisione e non
- alcuni dispositivi di I/O, come i dischi, possono essere usati
da più utenti contemporaneamente
- non c'è nessun problema se più utenti aprono dei file sullo stesso disco nel medesimo istante
- altri dispositivi, come le unità a nastro, devono invece essere dedicati a un singolo utente fino a che quell'utente non ha finito.
- il sistema operativo deve essere capace di gestire dispositivi
sia condivisi che dedicati in modo da evitare problemi
- l'indipendenza dal codice dei caratteri implica l'esistenza di
una rappresentazione interna, unificata per tutti i caratteri che
prende il nome di codice interno dei caratteri
- a ogni periferica si devono associare dei meccanismi di transcodifica per effettuare le opportune conversioni al momento dell'input o dell'output
- per quelle periferiche che possono gestire numerosi codici dei caratteri bisogna prevedere un meccanismo di transcodifica distinto per ogni codice supportato.
- l'indipendenza dal codice dei caratteri implica l'esistenza di
una rappresentazione interna, unificata per tutti i caratteri che
prende il nome di codice interno dei caratteri
- meccanismo di transcodifica
- la transcodifica viene effettuata subito dopo l'input ed appena prima dell'output, così da rendere necessaria la conoscenza del codice interno unificato esclusivamente a quei processi intimamente connessi con la gestione delle periferiche
- in generale il meccanismo di transcodifica consisterà in una tavola o, per alcuni casi, in un breve segmento di programma
- l'indipendenza dalle periferiche utilizzate comporta che i
programmi debbano operare non sulle unità reali, bensì su unità
virtuali, le quali sono variamente denominate:
- stream (Atlas)
- file speciali (UNIX)
- data set (IBM)
- questi flussi (stream) di dati vengono utilizzati all'interno
dei programmi senza riferimento alcuno alle unità periferiche
- il programmatore dirige semplicemente l'output e l'input verso
determinati stream, i quali sono poi associati alle periferiche
reali solitamente tramite il sistema operativo, sulla base delle
informazioni fornite dall'utente nella descrizione del lavoro
- la descrizione di un lavoro è una raccolta di informazioni fornite dall'utente, presentate dì solito all'inizio del lavoro, che servono al sistema operativo per decidere come e quando metterlo in esecuzione
- il programmatore dirige semplicemente l'output e l'input verso
determinati stream, i quali sono poi associati alle periferiche
reali solitamente tramite il sistema operativo, sulla base delle
informazioni fornite dall'utente nella descrizione del lavoro
- il sistema di I/O dovrebbe associare chiaramente le
caratteristiche delle periferiche alle unità stesse, anziché alle
routine che le gestiscono (i gestori delle unità periferiche,
driver)
- risulta possibile far sì che le periferiche presentino grosse
somiglianze
- le differenze funzionali tra le varie periferiche sono dovute,
in questo modo, da informazioni parametriche tratte dalle
caratteristiche della periferica
- la separazione delle caratteristiche delle periferiche si può realizzare codificandole in un descrittore di periferica collegato a ciascun dispositivo, servendosi quindi del descrittore quale fonte di informazioni per le routine di gestione delle periferiche
- le differenze funzionali tra le varie periferiche sono dovute,
in questo modo, da informazioni parametriche tratte dalle
caratteristiche della periferica
- risulta possibile far sì che le periferiche presentino grosse
somiglianze
- le informazioni caratteristiche circa un'unità periferica che
possono venir memorizzate nel descrittore relativo sono:
- 1) l'identificazione dell'unità;
- 2) le istruzioni che rendono operativa l'unità;
- 3) i puntatori rivolti alle tavole di transcodifica dei caratteri;
- 4) lo stato corrente (cioè, se l'unità è occupata, libera o rotta);
- 5) processo utente corrente (un puntatore verso il descrittore di quell'eventuale processo che utilizza al momento la periferica).
- tutti i descrittori di periferica possono essere inseriti assieme in una lista delle periferiche, indirizzata tramite il puntatore della tabella centrale
- alcuni dispositivi di I/O, come i dischi, possono essere usati
da più utenti contemporaneamente
- 8) organizzare il software a livelli
- l'idea di base è di organizzare il software come una sequenza di livelli in cui quelli inferiori si preoccupano di nascondere le peculiarità dell'hardware a quelli superiori, e quelli superiori si preoccupano di presentare agli utenti un'interfaccia piacevole, pulita e regolare.
- questi obiettivi possono essere raggiunti in modo chiaro ed
efficiente strutturando il software di I/0 in quattro livelli (dal
basso verso l'alto):
- 1) gestori di interruzione (in basso).
- 2) device driver (gestori dei dispositivi).
- 3) software di sistema operativo indipendente dal dispositivo.
- 4) software di livello utente (in alto).
- il livello 1 è gia stato trattato, in seguito tratteremo i livelli rimanenti
- 9) gestori di periferica (device driver)
- contiene tutto il codice dipendente dal dispositivo
- ogni device driver controlla un tipo dispositivo o al limite una classe di dispositivi strettamente imparentati
- il device driver impartisce i comandi al controllore del
dispositivo e si assicura che vengano correttamente eseguiti
- ad esempio il gestore del disco
- è la sola parte di sistema operativo che sa quanti registri ha quel particolare controllore del disco e a cosa servono.
- è a conoscenza di settori, tracce, cilindri, testine, movimenti del braccio, fattori di interleaving, controllo dei motori, tempi di posizionamento delle testine e di tutti gli altri meccanismi che fanno sì che il disco funzioni correttamente
- una richiesta tipica che soddisfa consiste nella lettura del
blocco n
- il primo passo nel soddisfare una richiesta di I/O è di
tradurla da termini astratti in termini concreti.
- per un driver di disco questo significa calcolare la posizione fisica del blocco richiesto sul disco, controllare che il motore del drive stia girando, determinare se il braccio è posizionato sul cilindro giusto e così via.
- dopo di che invia la sequenza corretta di comandi al controllore del disco
- il primo passo nel soddisfare una richiesta di I/O è di
tradurla da termini astratti in termini concreti.
- ad esempio il gestore del disco
- in termini generali, il compito di un gestore di dispositivo è
accettare richieste astratte dal software indipendente dal
dispositivo posto al di sopra di esso e far sì che queste richieste
siano soddisfatte traducendole in richieste concrete per il
dispositivo
- se il gestore è libero nel momento in cui la richiesta arriva,
inizia a eseguirla immediatamente.
- il device driver deve decidere quali operazioni richiedere al controllore e in quale sequenza
- determinati i comandi da inoltrare, il driver inizia a
richiederli scrivendo nei registri del controllore
- alcuni controllori possono gestire un solo comando alla volta, altri sono disponibili ad accettare una lista di comandi che poi eseguono per conto proprio, senza ulteriori interventi da parte del sistema operativo.
- dopo che i comandi sono stati inoltrati si possono verificare
due situazioni:
- il device driver deve attendere fino a che il controllore non soddisfa la richiesta, e quindi si blocca fino a che non arriva un'interruzione a sbloccarlo
- l'operazione termina senza alcun ritardo, e il driver non ha
bisogno di bloccarsi
- su alcuni terminali per effettuare lo scorrimento dello schermo basta scrivere alcuni byte nei registri del controllore.
- non è necessario alcun movimento meccanico e l'intera operazione può essere completata in pochi microsecondi.
- in ogni caso, dopo il completamento dell'operazione il driver
deve controllare gli eventuali errori
- se tutto è a posto, il driver in alcuni casi deve passare dei dati al software indipendente dal dispositivo (ad es. il blocco appena letto).
- infine, il driver restituisce al chiamante alcune informazioni di stato usate per riportare eventuali errori.
- se ci sono altre richieste accodate, ne può scegliere una e
avviarla
- altrimenti il driver si blocca in attesa della richiesta successiva
- se invece il gestore è già occupato, inserisce di norma la nuova richiesta in una coda di richieste pendenti da soddisfare non appena possibile.
- se il gestore è libero nel momento in cui la richiesta arriva,
inizia a eseguirla immediatamente.
- la gestione degli errori viene effettuata in larga parte dai
driver
- la maggior parte degli errori è fortemente dipendente dal
dispositivo, e solo il driver può sapere cosa fare :
- riprovare l'operazione
- ignorare l'errore
- andare in panic
- un tipico errore viene causato da un blocco danneggiato che non
può più essere letto.
- dopo che il driver ha provato a leggere il blocco un certo numero di volte, ci rinuncia e informa il software indipendente dal dispositivo.
- se l'errore è avvenuto mentre si leggeva un file utente, può essere sufficiente riportare una segnalazione al chiamante.
- viceversa, se l'errore ha avuto luogo mentre si leggeva una struttura dati critica per il sistema, come ad esempio un blocco contenente la bitmap che indica quali blocchi sono liberi, il sistema operativo può non avere altra scelta che stampare un messaggio di errore e quindi terminare
- la maggior parte degli errori è fortemente dipendente dal
dispositivo, e solo il driver può sapere cosa fare :
- 10) software di I/O indipendente dal dispositivo
- alcune porzioni del software di I/O sono specifiche del dispositivo ma una larga parte di esso ne è indipendente.
- il confine esatto tra il driver e il software indipendente dal
dispositivo varia a seconda del sistema
- alcune funzioni che svolte dal software indipendente dal dispositivo potrebbero in realtà essere effettuate dal driver, per motivi di efficienza o per altre ragioni.
- il compiti principali sono due
- realizzare le funzioni di I/O comuni a tutti i dispositivi
- fornire un'interfaccia uniforme al software di livello utente.
- un concetto importante di ogni sistema operativo è come
assegnare nomi a oggetti come i file e i dispositivi di I/O.
- il software indipendente dal dispositivo si preoccupa di mettere in corrispondenza i nomi simbolici dei dispositivi (usiamo qui il termine stream) con i driver appropriati
- la corrispondenza tra stream e tipi di periferiche per un
processo specifico si può registrare in una lista dei descrittori
di stream cui fa riferimento il puntatore del relativo descrittore
di processo
- l'assegnazione di un'unità particolare di un determinato tipo
viene effettuata nel momento in cui il processo utilizza per la
prima volta lo stream corrispondente.
- diciamo a questo punto che il processo apre lo stream, il quale può venir chiuso (intendendo che non va più usato) sia esplicitamente dal processo sia implicitamente al termine del medesimo.
- l'assegnazione di un'unità particolare di un determinato tipo
viene effettuata nel momento in cui il processo utilizza per la
prima volta lo stream corrispondente.
- in UNIX un nome di dispositivo, come /dev/tty00, specifica in
modo univoco l'i-node di un file speciale, e questo i-node contiene
il major device number (numero di dispositivo principale) che viene
utilizzato per localizzare il driver appropriato.
- l'i-node contiene inoltre il minor device number (o numero di dispositivo secondario), che viene passato come parametro al driver per specificare l'unità su cui leggere o scrivere.
- strettamente collegata all'assegnazione dei nomi è la
protezione.
- come fa il sistema a proibire l'accesso ai dispositivi agli
utenti non autorizzati?
- nella maggior parte dei personal computer non esiste alcuna
protezione.
- ogni processo può fare ciò che vuole
- nella maggior parte dei mainframe, invece, l'accesso ai dispositivi di I/O è del tutto proibito ai processi utente.
- in UNIX si usa uno schema più flessibile
- i file speciali corrispondenti ai dispositivi di I/O sono protetti dai soliti bit rwx
- l'amministratore di sistema può quindi stabilire i permessi appropriati per ogni dispositivo
- nella maggior parte dei personal computer non esiste alcuna
protezione.
- come fa il sistema a proibire l'accesso ai dispositivi agli
utenti non autorizzati?
- dischi diversi possono avere dimensioni di settore diverse
- è compito del software indipendente dal dispositivo nascondere
questi particolari e far sì che i livelli superiori vedano una
dimensione di blocco uniforme, ad esempio trattando più settori
come un singolo blocco logico.
- i livelli superiori trattano solo con dispositivi astratti che utilizzano tutti la stessa dimensione di blocco logico, indipendentemente dalla dimensione fisica del settore.
- è compito del software indipendente dal dispositivo nascondere
questi particolari e far sì che i livelli superiori vedano una
dimensione di blocco uniforme, ad esempio trattando più settori
come un singolo blocco logico.
- alcuni dispositivi a carattere consegnano i loro dati un byte
alla volta (ad es. i modem), mentre altri li forniscono in unità di
dimensione superiore (ad es. le interfacce di rete).
- anche queste differenze devono essere nascoste
- la gestione dei buffer è un altro argomento di rilievo
- nei dispositivi a blocchi, l'hardware generalmente richiede che
si legga e scriva ogni volta un numero intero di blocchi, mentre i
processi utente sono liberi di leggere e scrivere secondo unità
arbitrarie.
- se un processo utente scrive mezzo blocco
- il sistema operativo normalmente conserverà i dati al suo interno fino a che non si scrivono i dati necessari a completare il blocco
- solo a questo punto il blocco potrà essere finalmente scritto sul disco.
- se un processo utente scrive mezzo blocco
- per quel che riguarda i dispositivi a carattere
- gli utenti possono scrivere dati verso il sistema più
velocemente di quanto i dati stessi possano essere inoltrati in
uscita, richiedendo quindi l'uso di buffer.
- gli ingressi da tastiera che arrivano prima di essere effettivamente richiesti devono essere inseriti in un buffer
- gli utenti possono scrivere dati verso il sistema più
velocemente di quanto i dati stessi possano essere inoltrati in
uscita, richiedendo quindi l'uso di buffer.
- nei dispositivi a blocchi, l'hardware generalmente richiede che
si legga e scriva ogni volta un numero intero di blocchi, mentre i
processi utente sono liberi di leggere e scrivere secondo unità
arbitrarie.
- l'algoritmo per localizzare un blocco libero è indipendente dal
dispositivo
- quando un file viene creato e riempito di dati, gli si devono allocare nuovi blocchi su disco. per effettuare quest'allocazione il sistema operativo ha bisogno di una lista o di una tabella di bit (bitmap) relativa ai blocchi liberi
- alcuni dispositivi, come i masterizzatori di CD-ROM, possono
essere usati da un solo processo alla volta
- è compito del sistema operativo esaminare le richieste per
l'uso del dispositivo e accettarle o respingerle, a seconda che il
dispositivo richiesto sia o meno disponibile.
- un modo semplice per gestire queste richieste è di imporre che
i processi effettuino direttamente le OPEN sui file speciali dei
dispositivi.
- se il dispositivo non è disponibile, la OPEN fallirà.
- la chiusura di un simile dispositivo dedicato corrisponderà quindi al suo rilascio con l'operazione di CLOSE.
- un modo semplice per gestire queste richieste è di imporre che
i processi effettuino direttamente le OPEN sui file speciali dei
dispositivi.
- è compito del sistema operativo esaminare le richieste per
l'uso del dispositivo e accettarle o respingerle, a seconda che il
dispositivo richiesto sia o meno disponibile.
- 11) software di I/O nello spazio utente
- benché la maggior parte del software di I/O sia contenuto nel
nucleo del S.O. una piccola porzione formata da librerie da
collegare ai programmi utente (e perfino di interi programmi)
risiedono al di fuori.
- le chiamate di sistema, comprese le chiamate per l'I/O, sono normalmente costituite da procedure di libreria.
- quando un programma C contiene la chiamata
- count = write(fd, buffer, nbytes);
- la procedura di libreria write sarà collegata con il programma e come tale farà parte del programma binario presente in memoria a tempo di esecuzione
- l'insieme di tutte queste procedure di libreria è chiaramente
una parte del sistema di I/O
- in genere queste procedure fanno poco più che mettere i loro
parametri nel posto richiesto dalle chiamate di sistema
- ma la definizione del formato degli ingressi e delle uscite viene fatta da procedure di libreria
- esempi tratti dal C
- funzione printf
- che prende in ingresso una stringa che specifica il formato ed eventualmente altre variabili, costruisce una stringa ASCII, e chiama quindi la write per stampare la stringa.
- funzione scanf
- che legge i dati e li memorizza nelle variabili descritte in una stringa che specifica il formato utilizzando la stessa sintassi della printf.
- la libreria standard di I/O contiene alcune procedure che riguardano l'I/O e vengono eseguite come parte dei programmi utente.
- funzione printf
- in genere queste procedure fanno poco più che mettere i loro
parametri nel posto richiesto dalle chiamate di sistema
- il software di I/O può essere organizzato come
- sistema strutturato a processi
- avviene uno scambio di messaggi tra processi indipendenti che
girano nello spazio utente e device driver che lavorano nello
spazio di nucleo
- alcuni processi forniscono ai processi utente la possibilità di effettuare l'I/O interfacciandosi con i device driver
- il file system ad esempio chiama il device driver attraverso i messaggi e quindi offre al processo utente il servizio richiesto (entrambi sono processi dello spazio utente)
- avviene uno scambio di messaggi tra processi indipendenti che
girano nello spazio utente e device driver che lavorano nello
spazio di nucleo
- sistema monolitico (usato da UNIX)
- il processo nello spazio utente accede ai servizi offerti nello
spazio nucleo attraverso una trap (system call)
- il file system ad esempio chiama il device driver come una procedura (si trovano entrambi nello spazio di nucleo)
- questo approccio è molto efficiente
- le chiamate a procedura sono molto più veloci dell'invio di messaggi
- il processo nello spazio utente accede ai servizi offerti nello
spazio nucleo attraverso una trap (system call)
- sistema strutturato a processi
- il software di I/O di livello utente è costituito, oltre che da
procedure di libreria, anche dal sistema di spooling
- un metodo che consente di gestire i dispositivi dedicati di I/O in un sistema multiprogrammato
- benché la maggior parte del software di I/O sia contenuto nel
nucleo del S.O. una piccola porzione formata da librerie da
collegare ai programmi utente (e perfino di interi programmi)
risiedono al di fuori.
- 1) indipendenza dal codice dei caratteri
- le procedure di I/O
- una richiesta caratteristica proveniente da un processo utente
costituirà una chiamata al sistema operativo nella forma generica:
- DOIO (stream, modo, quantità, destinazione, semaforo)
- Dove:
- DOIO - è il nome di una procedura di I/O di sistema;
- stream - è il numero di stream su cui deve aver luogo l'I/O;
- modo - indica quale tipo di operazione è richiesta: per esempio trasferimento di dati e riavvolgimento nastro; può indicare inoltre, se pertinente, quale codice di caratteri va utilizzato;
- quantità - è la quantità di dati eventualmente da trasferire;
- destinazione - (o sorgente) è la locazione verso la quale (o dalla quale) deve avvenire l'eventuale trasferimento;
- semaforo - è l'indirizzo di un semaforo di "richiesta soddisfatta" che deve essere soggetto ad un signal quando viene completata l'operazione di I/O.
- la procedura di I/O denominata DOIO è rientrante, così da poter
essere usata contemporaneamente da più processi.
- la sue funzioni sono
- associare il numero di stream alla periferica reale più
opportuna
- la periferica corrispondente al flusso in questione è determinata dalle informazioni presenti nella lista dei descrittori di stream relativa al processo chiamante al momento dell'apertura del flusso stesso
- verificare la corrispondenza dei parametri forniti
- si verifica la corrispondenza dei parametri rispetto alle
informazioni contenute nel descrittore della periferica
- nel caso in cui si riscontrasse un errore si può rilasciare la risorsa e tornare al processo chiamante
- un particolare tipo di controllo eventualmente attuabile consiste nel verificare che la periferica sia in grado di operare nel modo di funzionamento voluto
- un altro consiste nello stabilire se l'estensione e la
destinazione del trasferimento di dati corrispondono al modo di
funzionamento.
- nel caso di periferiche in grado di trasferire solo caratteri singoli, la quantità di dati del trasferimento deve essere pari ad 1 ed essere destinata ad un registro o ad una locazione di memoria.
- per quelle periferiche che trasferiscono direttamente in memoria blocchi di dati, la quantità specificata deve equivalere all'estensione del blocco (fissa o variabile, a seconda della periferica) che deve essere destinato alla locazione di memoria dove deve avere inizio il trasferimento
- si verifica la corrispondenza dei parametri rispetto alle
informazioni contenute nel descrittore della periferica
- iniziare il soddisfacimento della richiesta
- una volta completati i controlli, la procedura di I/O riunisce i parametri relativi alla richiesta in un blocco di richiesta di I/O (IORB - I/O Request Block) che provvede poi ad aggiungere ad una coda formata da blocchi analoghi, i quali rappresentano le altre richieste di utilizzo della stessa periferica.
- per quanto concerne queste ultime, possono provenire dallo stesso processo o, nel caso di una periferica condivisibile, come il disco magnetico, da altri processi. La coda delle richieste alla periferica viene annessa al descrittore della periferica relativa (vedi figura 6.2) ed è gestita da un processo distinto denominato routine di gestione della periferica (device driver)
- la procedura di I/O segnala al gestore della periferica di aver sistemato nella coda una richiesta, svolgendo un'operazione di signal su un semaforo di richiesta in sospeso (o pendente) collegato alla periferica e contenuto nel descrittore della stessa.
- analogamente, dopo il completamento dell'operazione di I/O, il
gestore della periferica ne informa il processo utente tramite un
semaforo di richiesta soddisfatta, il cui indirizzo, già parametro
della procedura di I/O, è stato passato al gestore come elemento
dello IORB.
- tale semaforo può essere inizializzato sia dal processo utente che dalla procedura di I/O al momento della creazione dello IORB
- associare il numero di stream alla periferica reale più
opportuna
- la sue funzioni sono
- La routine completa di I/O è
- procedure DOIO (stream, modo, quantità, destinazione, semaforo);
- begin cerca la periferica nel descrittore di processo;
- controlla i parametri a fronte delle caratteristiche della periferica;
- if errore then uscita per errore;
- raggruppa lo IORB;
- aggiungi lo IORB alla coda delle richieste alla periferica;
- signal (richiesta in sospeso)
- end;
- un gestore delle periferiche è costituito da un processo
responsabile del soddisfacimento delle richieste presenti in una
coda di richieste alla periferica e della segnalazione, al processo
chiamante, del completamento dell'operazione relativa.
- vi è un gestore distinto per ogni periferica, ma, poiché tutti i gestori funzionano in modo analogo, possono utilizzare programmi in condivisione.
- le eventuali diversità di comportamento tra i singoli gestori vengono dedotte dalle caratteristiche memorizzate nei descrittori delle periferiche interessate.
- un gestore di periferica opera in ciclo continuo nel corso del
quale
- toglie uno IORB dalla coda delle richieste
- inizia l'operazione di I/O corrispondente
- attende il completamento dell'operazione e segnala al processo chiamante l'avvenuto completamento.
- il ciclo completo per un'operazione di input è il seguente:
- repeat indefinitamente
- begin wait (richiesta in sospeso);
- prendi uno IORB dalla coda delle richieste;
- preleva gli estremi della richiesta;
- inizia l'operazione di I/O;
- wait (operazione completata);
- if errore then registra l'informazione d'errore;
- transcodifica carattere/i se necessario;
- trasferisci dati alla destinazione;
- signal (richiesta soddisfatta);
- cancella IORB
- end;
- annotazioni sul ciclo
- il semaforo "richiesta in sospeso"
- è contenuto nel descrittore della periferica
- è soggetto ad un'operazione di signal da parte della procedura di I/O ogniqualvolta quest'ultima provvede a mettere uno IORB nella coda delle richieste della periferica in questione.
- se la coda è vuota, il semaforo ha valore 0 ed il gestore della periferica viene messo in stato di sospensione.
- il gestore della periferica può prendere uno IORB dalla coda in
base ad un qualunque algoritmo di priorità prescelto.
- solitamente risulta adeguato un algoritmo di tipo FIFO, ma il gestore potrebbe essere influenzato dalle informazioni di priorità messe nello IORB da parte della procedura di I/O.
- nel caso si tratti di un'unità a disco, il gestore della periferica potrebbe soddisfare le richieste secondo un ordine che rende minimi i movimenti della testina
- le istruzioni richieste per avviare l'operazione di I/O possono essere prelevate dalle caratteristiche della periferica contenute nel suo descrittore.
- il semaforo "operazione completata"
- è soggetto ad un'operazione di signal da parte della routine di interrupt in seguito alla generazione di un interrupt per la periferica in questione.
- il programma di massima per la routine di interrupt, in cui si
entra da quella di gestione degli interrupt di primo livello, è il
seguente:
- #### manca qualcosa ####
- localizza descrittore della periferica
- signal (operazione completata)
- è contenuto nel descrittore di periferica.
- si noti che la routine di interrupt è estremamente breve
- le attività ausiliarie di preparazione nel loro insieme vengono svolte dal gestore della periferica, il quale opera nel modo non privilegiato, come qualsiasi normale processo.
- il riscontro degli errori si effettua consultando lo stato
della periferica al completamento dell'operazione.
- se si è verificata una situazione d'errore, ad esempio un errore di parità, l'informazione viene depositata in una locazione d'errore il cui indirizzo è inserito nello IORB ad opera della procedura di I/O.
- la transcodifica dei caratteri viene effettuata in base al modo
specificato nello IORB e le tabelle relative sono collegate tramite
il puntatore del descrittore di periferica.
- nel caso di un'operazione di output, il prelievo dei dati dalla fonte relativa e l'eventuale transcodifica dei caratteri avvengono prima dell'operazione anziché dopo
- il semaforo "richiesta in sospeso"
- è importante notare che, nello schema illustrato, il processo
richiedente si evolve in modo asincrono rispetto al gestore della
periferica, consentendogli di svolgere altre attività di calcolo o
di effettuare altre richieste di I/O durante il soddisfacimento
della richiesta originaria.
- è necessario conservare il processo richiedente solamente in
quei casi in cui l'operazione di I/O sia incompleta al momento
dell'esecuzione di wait (richiesta soddisfatta).
- lo svantaggio derivante da questa soluzione consiste nel fatto
che il processo richiedente deve assumersi il compito di
sincronizzare le sue attività con quelle del gestore della
periferica.
- per esempio, non deve tentare l'utilizzazione di dati di input che non sono ancora stati messi a disposizione.
- ciò significa che l'autore del processo deve essere consapevole che le operazioni di I/O non sono istantanee e che devono venir messe in grado di raggiungere la sincronizzazione voluta impiegando adeguatamente il semaforo di richiesta soddisfatta.
- lo svantaggio derivante da questa soluzione consiste nel fatto
che il processo richiedente deve assumersi il compito di
sincronizzare le sue attività con quelle del gestore della
periferica.
- una soluzione alternativa consiste nell'inserire l'onere della
sincronizzazione all'interno della procedura di I/O, che fa parte
del sistema operativo.
- lo scopo si può raggiungere rendendo il semaforo richiesta
soddisfatta locale alla procedura di I/O (il che implica che il suo
indirizzo non venga più fornito dal processo richiedente) ed
inserendo nella stessa, subito prima della sua uscita, le seguenti
operazioni:
- wait(richiesta soddisfatta);
- verifica locazione d'errore;
- il ritardo implicito in un'operazione di I/O a questo punto
viene mascherato entro il sistema operativo
- per quanto riguarda il processo richiedente, l'operazione è
istantanea, nel senso che si può supporre completata quando viene
eseguita l'istruzione successiva alla richiesta.
- per esprimere il concetto in altri termini, il processo richiedente è in esecuzione su una macchina virtuale in cui le operazioni di I/O vengono realizzate per mezzo di un'unica istruzione istantanea.
- per quanto riguarda il processo richiedente, l'operazione è
istantanea, nel senso che si può supporre completata quando viene
eseguita l'istruzione successiva alla richiesta.
- lo scopo si può raggiungere rendendo il semaforo richiesta
soddisfatta locale alla procedura di I/O (il che implica che il suo
indirizzo non venga più fornito dal processo richiedente) ed
inserendo nella stessa, subito prima della sua uscita, le seguenti
operazioni:
- è necessario conservare il processo richiedente solamente in
quei casi in cui l'operazione di I/O sia incompleta al momento
dell'esecuzione di wait (richiesta soddisfatta).
- una richiesta caratteristica proveniente da un processo utente
costituirà una chiamata al sistema operativo nella forma generica:
- gestione del buffer
- buffering
- consiste nell'eseguire i trasferimenti I/O prima che ne venga fatta effettiva richiesta
- evita gravosi appesantimenti del sistema dovuti alla
commutazione dei processi in seguito a ripetute operazioni di I/O
- senza un buffer, un processo che esegue ripetuti trasferimenti sullo stesso stream sarà soggetto ad altrettante sospensioni dovute al semaforo wait(richiesta soddisfatta) nel corso dei trasferimenti stessi
- uso di un solo buffer
- i trasferimenti di input vengono effettuati dal sistema
operativo su una zona di memoria denominata buffer di input.
- il processo utente prende i propri dati dal buffer ed è obbligato ad attendere solo quando il buffer si svuota.
- al verificarsi di quest'ultima situazione, il sistema operativo riempie nuovamente il buffer ed il processo può continuare.
- i trasferimenti di output provenienti da un processo vengono
destinati ad un buffer di output che il sistema operativo provvede
a vuotare completamente quando è pieno.
- il processo deve mettersi in attesa solo se tenta di emettere un dato prima che il sistema abbia svuotato il buffer.
- i trasferimenti di input vengono effettuati dal sistema
operativo su una zona di memoria denominata buffer di input.
- uso di due buffer (bufferizzazione doppia)
- consente di affinare il procedimento precedente solo
- un processo trasferisce i dati verso (oppure da) uno dei due
buffer, mentre il sistema operativo svuota (oppure riempie)
l'altro.
- in questo modo si garantisce che il processo deve attendere solo se ambedue i buffer sono pieni (o vuoti) prima dell'intervento da parte del sistema operativo.
- quest'ultima situazione si verifica solamente quando un processo esegue un trasferimento di I/O a raffica (burst) ed in tal caso si può spesso risolvere il problema aggiungendo un numero ancora più elevato di buffer (bufferizzazione multipla).
- non esiste un numero di buffer sufficiente se un processo
richiede I/O ad una velocità notevolmente maggiore di quella di
esercizio delle periferiche.
- l'utilità dei buffer è limitata all'eliminazione dei picchi
nelle richieste di I/O, in situazioni in cui la richiesta media non
è superiore a quella che le periferiche di I/O sono in grado di
soddisfare.
- in generale si può dire che tanto più alti sono questi valori di punta tanto maggiore è il numero di buffer necessari per ottenere l'uniformità di trasferimento
- l'utilità dei buffer è limitata all'eliminazione dei picchi
nelle richieste di I/O, in situazioni in cui la richiesta media non
è superiore a quella che le periferiche di I/O sono in grado di
soddisfare.
- inserire un buffer per un dato stream può richiedere un
opportuno enunciato di statement all'interno della descrizione del
lavoro relativo.
- se si prevede l'impiego di buffer, l'utente potrà specificarne
il numero oppure lasciare che sia il sistema ad occuparsene;
- in quest'ultimo caso il valore assunto per default è solitamente due.
- il sistema operativo provvede all'allocazione dello spazio necessario ai buffer al momento dell'apertura dello stream e ne registra l'indirizzo nel descrittore dello stream stesso.
- se si prevede l'impiego di buffer, l'utente potrà specificarne
il numero oppure lasciare che sia il sistema ad occuparsene;
- per consentire lo svolgimento delle operazioni in presenza di
buffer è necessaria una procedura di I/O leggermente diversa.
- questa gestisce una richiesta di input prelevando il dato successivo dal buffer opportuno e passandolo direttamente al processo richiedente.
- solo se un buffer si svuota, la procedura genera uno IORB e segnala al gestore della periferica che è necessario fornire più input.
- all'apertura dello stream, la procedura di I/O genera IORB sufficienti a provocare il riempimento di tutti i buffer.
- il gestore della periferica agisce come in precedenza, avviando un trasferimento di dati sul buffer corrispondente alla locazione indicata nello IORB.
- considerazioni analoghe sono valide, con le debite
differenziazioni, anche per le richieste di output.
- in entrambi i casi, la procedura di I/O ed il gestore della periferica congiuntamente rappresentano una variante della coppia produttore/consumatore descritta nel capitolo 3.
- la procedura di I/O per operazioni effettuate tramite buffer
può essere richiamata da un processo utente tramite un'istruzione
scritta nella forma generica
- DOBUFFIO (stream, modo, destinazione)
- dove
- stream, modo e destinazione hanno lo stesso significato descritto a proposito della procedura DOIO
- la quantità di informazioni trasferite sarà pari ad un unico dato.
- eventuali ritardi derivanti da situazioni relative a buffer
pieni o vuoti vengono mascherati all'interno della procedura di I/O
- non risulta necessario fornire un indirizzo di semaforo tra i parametri.
- il tipo dell'eventuale tecnica di bufferizzazione impiegata,
gli indirizzi dei buffer ed i semafori ad uso delle procedure di
I/O sono tutti elementi cui si può avere accesso dalla lista dei
descrittori di stream relativa al processo chiamante
- la prima di queste informazioni può servire a determinare il tipo di procedura di I/O da richiamare per effettuare un trasferimento
- buffering
- le unità di supporto ai file
- è chiamata così ogni periferica in grado di memorizzare un file
- quando si effettua I/O da periferiche sequenziali, come ad esempio la tastiera, è sufficiente il nome della periferica per portare a termine l'operazione, invece se si effettua su periferiche ad accesso casuale (ogni locazione di memoria può essere indirizzata in maniera immediata ed indipendente), come un disco, oltre al nome della periferica è necessario indicare su quale locazione di memoria si vuole effettuare l'operazione
- un file (per il momento)
- è un'area dati potenzialmente esistente sul supporto
- solitamente ha una dimensione definita arbitrariamente all'atto della sua creazione o aggiornamento
- è caratterizzato da un nome univoco che può servire al sistema operativo per determinarne la locazione sul supporto relativo
- una directory
- è un indice contenente i nomi dei file e le corrispondenti locazioni
- è mantenuta dal sistema operativo
- quando si deve trasferire verso (o da) un'unità di supporto ai
file un determinato stream di dati, quest'ultimo viene associato
nella descrizione del lavoro al nome di un file specifico, anziché
al nome dell'unità.
- per esempio, uno statement caratteristico di descrizione del
lavoro potrebbe essere il seguente:
- INPUT1 = "DATI_DI_TEST"
- indicante che i dati dello stream N.1 devono provenire dal file
denominato DATI_DI_TEST.
- all'apertura dello stream, il sistema operativo cerca nella
directory il nome del file per trovare l'unità e la locazione in
cui è memorizzato il file.
- tale procedura, nota sotto il nome di "apertura del file" e comprende vari controlli
- all'apertura dello stream, il sistema operativo cerca nella
directory il nome del file per trovare l'unità e la locazione in
cui è memorizzato il file.
- poiché può trattarsi di un'operazione di lunga durata, non è
consigliabile ripeterla per ogni trasferimento di dati.
- di conseguenza, ogniqualvolta si apre un file, si crea anche un descrittore di file, per contenervi quelle informazioni necessarie per i trasferimenti che avverranno nell'immediato futuro.
- tali informazioni comprendono
- l'indirizzo del descrittore della periferica su cui è memorizzato il file
- la locazione del file su quella periferica
- permessi di scrittura o lettura
- i particolari inerenti la sua organizzazione interna.
- nell'opportuno descrittore di stream del processo che effettua
l'apertura del file è inserito un puntatore al descrittore del file
- il descrittore del file aggiunge anche altre informazioni oltre a quelle necessarie per associare gli stream alle unità reali
- le procedure di I/O che effettuano l'associazione per ogni trasferimento di dati possono venir modificate facilmente, così da tener conto di queste informazioni durante il raggruppamento degli IORB.
- per esempio, uno statement caratteristico di descrizione del
lavoro potrebbe essere il seguente:
- gestione dello spool
- la stampante è un tipico dispositivo gestito mediante tecniche
di spooling
- tecnicamente è possibile consentire a ogni processo utente di
aprire lo speciale file a caratteri corrispondente alla stampante
- se però un processo apre il file e rimane bloccato per ore nessun altro processo potrebbe stampare nel frattempo
- una soluzione consiste nel creare un processo, chiamato demone,
e una directory speciale, chiamata la directory di spooling
- per stampare un file, il processo genera in anticipo l'intero file da stampare e lo mette nella directory di spooling.
- il demone è il solo processo ad avere il permesso di usare il
file speciale della stampante
- ha il compito di stampare i file contenuti nella directory di spool
- in questo modo, proteggendo il file speciale dall'uso diretto da parte degli utenti, si elimina il rischio che ci sia qualcuno che lo tiene aperto inutilmente a lungo.
- tecnicamente è possibile consentire a ogni processo utente di
aprire lo speciale file a caratteri corrispondente alla stampante
- questa tecnica viene usata in molte circostanze
- il trasferimento dei file sulla rete viene spesso effettuato da
un demone di rete
- per inviare un file da qualche parte, l'utente lo inserisce in
una directory di spooling di rete
- in seguito, il demone di rete lo prende e lo trasmette
- per inviare un file da qualche parte, l'utente lo inserisce in
una directory di spooling di rete
- la posta elettronica di Internet
- internet è costituita da milioni di macchine sparse per il mondo e comunicanti mediante un gran numero di reti di computer.
- per inviare un messaggio a qualcuno, l'utente invoca un
programma come send, che accetta l'e-mail da inviare e la deposita
in una directory di spooling, da dove verrà successivamente
trasmessa.
- l'intero sistema di posta elettronica viene eseguito al di fuori del sistema operativo.
- il trasferimento dei file sulla rete viene spesso effettuato da
un demone di rete
- in molti sistemi operativi tutto l'I/O relativo a periferiche
soggette ad utilizzo intensivo è organizzato tramite lo spool
- questa tecnica vale in modo particolare per le periferiche non condivisibili
- invece di eseguire un trasferimento direttamente sulla periferica relativa allo stream, le procedure di I/O lo effettuano su qualche supporto intermedio (solitamente un disco).
- il compito di spostare i dati tra il disco e la periferica necessaria viene attribuito ad un processo a parte, denominato spooler, il quale è associato a quella periferica
- esempio di funzionamento, stampante parallela
- tutto l'output relativo alla stampante viene inviato allo spool
- ad ogni processo che apre uno stream della stampante parallela
viene assegnato un file anonimo su disco e tutto l'output contenuto
nello stream viene inviato a questo file da parte della procedura
di I/O
- in effetti, il file funge da stampante parallela virtuale
- quando si richiude lo stream
- il file in questione viene aggiunto ad una coda contenente file analoghi creati da altri processi, tutti in attesa di essere stampati
- lo spooler della stampante parallela preleva i file dalla coda
e li invia alla stampante
- si presume, ovviamente, che la velocità della stampante sia sufficiente per gestire tutti i file di output generati entro un determinato intervallo di tempo
- la struttura schematica di uno spooler è la seguente:
- repeat indefinitamente
- begin wait (dati da mettere in spool);
- preleva il file dalla coda;
- apri il file;
- repeat fino alla fine del file
- begin DOIO (parametri per lettura da disco);
- wait (richiesta disco soddisfatta);
- DOIO (parametri per output su stampante parallela);
- wait (richiesta stampante soddisfatta)
- end
- end;
- la struttura in pratica sarà modificata per consentire l'inserimento di un buffer per i dati tra disco e stampante;
- sul semaforo dati da mettere in spool viene svolta un'operazione di signal da qualsiasi processo che chiuda uno stream della stampante parallela (che completa, cioè, un file di output);
- i dati in coda di output non devono essere necessariamente elaborati col metodo FIFO; lo spooler potrebbe privilegiare, ad esempio, i file corti anziché quelli lunghi.
- riassumendo, possiamo dire che la funzione di spool serve ad
uniformare il carico delle richieste per quelle periferiche
soggette ad utilizzo più consistente.
- diminuisce inoltre la probabilità di situazioni di stallo dovute ad un'imprudente allocazione delle periferiche
- è relativamente semplice produrre copie multiple dello stesso output senza dover rieseguire il lavoro
- richiede grande quantità di spazio su disco necessario a contenere le code di input e di output, e genera notevole movimento sul canale del disco,
- la funzione di spool non è realizzabile in una situazione in cui si operi in tempo reale, dove le transazioni di I/O devono avvenire immediatamente
- la stampante è un tipico dispositivo gestito mediante tecniche
di spooling