Introduzione ai sistemi operativi con UNIX
Prec Succ

3. Alcune system call di UNIX per l'I/O

  1. read
  2. write
  3. open
  4. Elenco delle principali system call

I programmi utente per accedere alle funzioni messe a disposizione dal sistema operativo utilizzano chiamate di procedura ben definite, dette anche chiamate di sistema o richiami di sistema o system call. Programmando in linguaggio macchina i386 le system call si invocano come interruzioni software, tramite l'istruzione INT, mentre l'istruzione IRET si occupa di ritornare il controllo al punto di interruzione. La INT prima salva il registro dei flag e altri registri che puntano alla prossima istruzione da eseguire (nella architettura i386 il salvataggio avviene sullo stack) e poi carica quest'ultimi con un valore che preleva da un array detto vettore delle interruzioni (interrupt vector table). L'argomento di INT rappresenta l'indice in questo array. L'esecuzione proseguirà quindi alla locazione indicata dai nuovi valori del puntatore all'istruzione. La IRET ricarica nei rispettivi registri i valori dei registri salvati da INT sullo stack e quindi l'esecuzione proseguirà alla istruzione successiva alla INT.

Esistono wrapper per utilizzare le system call anche in alcuni linguaggi di programmazione ad alto livello, come ad es. il C nel caso del sistema operativo UNIX. Questi wrapper sono parte della libreria standard del C, ma sono accessibili anche programmando in linguaggio macchina tramite l'istruzione di macchina di chiamata di procedura CALL (ovviamente occorre usare le opportune istruzioni di macchina per passare correttamente i parametri prima della CALL, così come fa il compilatore C). Ogni system call ha un nome, dei parametri e ritorna un valore di stato o codice di stato. I parametri vengono passati alla routine del sistema operativo che implementa la system call nei registri, in una tabella di memoria di cui viene passato l'indirizzo o tramite lo stack. La routine viene poi invocata come una interruzione avviata via software e al ritorno il controllo viene restituito al programma chiamante. Il meccanismo è simile sia nel sistema operativo DOS che in UNIX.

Il sistema DOS tuttavia non disponeva di alcun meccanismo di protezione e rendeva possibile ai programmi di utente l'accesso diretto ai dispositivi ed alle system call di più basso livello che mette a disposizione il BIOS. In UNIX invece esistono due modi operativi: il modo kernel (kernel mode o supervisor mode) che è quello che permette il controllo completo dell'hardware (tutte le istruzioni di macchina sono eseguibili in questa modalità) e sotto cui opera il sistema operativo e le sue system call e il modo utente (user mode) che è l'ambiente più ristretto di esecuzione dei programmi di utente o delle librerie che li compongono (alcune istruzioni sono riservate al modo kernel e ne è illegale l'uso in modo utente). In user mode l'hardware fornisce dei meccanismi di protezione che impediscono l'accesso diretto ai dispositivi; questo può avvenire quindi solo attraverso le system call del nucleo, che in questo modo può imporre dei limiti ai programmi utenti per assicurare una migliore sicurezza del sistema.

Per questa ragione infatti, ad esempio, non è possibile in UNIX che un programma eseguito con i privilegi di un utente ordinario possa modificare con facilità alcune parti del sistema operativo o le utility di sistema inserendo codice di programmi virus e similari. Nel sistema DOS invece questo era un problema di sicurezza molto frequente.

Iniziamo a fare pratica con le system call di UNIX, alcune delle quali sono appunto dedicate alla gestione dei processi, un argomento fondamentale per la comprensione dei sistemi operativi che tratteremo ampiamente nel seguito. Ora per semplicità inizieremo con alcune system call per l'I/O che sono di più semplice comprensione e sono comunque fondamentali. Il prerequisito è una conoscenza elementare del C o di linguaggi simili. Per approfondimenti si rimanda al manuale UNIX in linea. Ad esempio per read(2) la manpage si invoca con:

   $ man 2 read

La sezione 2 contiene l'help su tutte le system call, mentre la sezione 3 sulle funzioni della libreria del C, che sono di più alto livello (ricordo che il C è un linguaggio portabile tra diversi sistemi operativi). Queste sono le due sezioni del manuale a cui faremo maggiormente riferimento. Occasionalmente faremo riferimento anche a pagine della sezione 5 che contiene le descrizioni dei formati dei file e della sezione 1 che spiega i comandi di utente. Per maggiori informazioni su come cercare e visualizzare le pagine del manuale UNIX, date un'occhiata a man(1), apropos(1) e whatis(1).

   $ man man

Per i dettagli ho fatto riferimento alla versione di UNIX FreeBSD. Purtroppo infatti i dettagli di comportamento delle system call variano da sistema a sistema anche se in linea generale il comportamento è molto simile e ci sono degli standard come il "POSIX.1". In FreeBSD intro(2) è la pagina di manuale che introduce all'argomento delle chiamate di sistema. Ci sono diverse pagine di manuale che si chiamano intro, ma sono in sezioni differenti e ciascuna rappresenta una introduzione alla sezione del manuale a cui appartiene:

$ whatis intro
intro(1)                 - introduction to general commands (tools and utilities)
intro(2)                 - introduction to system calls and error numbers
intro(3)                 - introduction to the C libraries
intro(4)                 - introduction to devices and device drivers
intro(5)                 - introduction to file formats
intro(6)                 - introduction to games
intro(7)                 - miscellaneous information pages
intro(8)                 - introduction to system maintenance and operation commands
intro(9)                 - introduction to system kernel interfaces

Prec Indice Succ
FreeBSD   read