\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct dirent {
- ino_t d_ino; /* inode number */
- off_t d_off; /* offset to the next dirent */
- unsigned short int d_reclen; /* length of this record */
- unsigned char d_type; /* type of file */
- char d_name[256]; /* We must not include limits.h! */
-};
- \end{lstlisting}
+ \includestruct{listati/dirent.c}
\end{minipage}
\normalsize
\caption{La struttura \structd{dirent} per la lettura delle informazioni dei
\cmd{ls}).
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h> /* directory */
-#include <stdlib.h> /* C standard library */
-#include <unistd.h>
-
-/* computation function for DirScan */
-int do_ls(struct dirent * direntry);
-/* main body */
-int main(int argc, char *argv[])
-{
- ...
- if ((argc - optind) != 1) { /* There must be remaing parameters */
- printf("Wrong number of arguments %d\n", argc - optind);
- usage();
- }
- DirScan(argv[1], do_ls);
- exit(0);
-}
-/*
- * Routine to print file name and size inside DirScan
- */
-int do_ls(struct dirent * direntry)
-{
- struct stat data;
-
- stat(direntry->d_name, &data); /* get stat data */
- printf("File: %s \t size: %d\n", direntry->d_name, data.st_size);
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/my_ls.c}
+ \end{minipage}
\caption{Esempio di codice per eseguire la lista dei file contenuti in una
directory.}
\label{fig:file_my_ls}
valore di ritorno per indicare una esecuzione senza errori.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h> /* directory */
-#include <stdlib.h> /* C standard library */
-#include <unistd.h>
-
-/*
- * Function DirScan:
- *
- * Input: the directory name and a computation function
- * Return: 0 if OK, -1 on errors
- */
-int DirScan(char * dirname, int(*compute)(struct dirent *))
-{
- DIR * dir;
- struct dirent *direntry;
-
- if ( (dir = opendir(dirname)) == NULL) { /* oper directory */
- printf("Opening %s\n", dirname); /* on error print messages */
- perror("Cannot open directory"); /* and then return */
- return -1;
- }
- fd = dirfd(dir); /* get file descriptor */
- fchdir(fd); /* change directory */
- /* loop on directory entries */
- while ( (direntry = readdir(dir)) != NULL) { /* read entry */
- if (compute(direntry)) { /* execute function on it */
- return -1; /* on error return */
- }
- }
- closedir(dir);
- return 0;
-}
-
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/DirScan.c}
+ \end{minipage}
\caption{Codice della routine di scansione di una directory contenuta nel
file \file{DirScan.c}.}
\label{fig:file_dirscan}
\footnotesize
\centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct stat {
- dev_t st_dev; /* device */
- ino_t st_ino; /* inode */
- mode_t st_mode; /* protection */
- nlink_t st_nlink; /* number of hard links */
- uid_t st_uid; /* user ID of owner */
- gid_t st_gid; /* group ID of owner */
- dev_t st_rdev; /* device type (if inode device) */
- off_t st_size; /* total size, in bytes */
- unsigned long st_blksize; /* blocksize for filesystem I/O */
- unsigned long st_blocks; /* number of blocks allocated */
- time_t st_atime; /* time of last access */
- time_t st_mtime; /* time of last modification */
- time_t st_ctime; /* time of last change */
-};
- \end{lstlisting}
+ \includestruct{listati/stat.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{stat} per la lettura delle informazioni dei
Ad esempio se si volesse impostare una condizione che permetta di controllare
se un file è una directory o un file ordinario si potrebbe definire la macro
di preprocessore:
-\begin{lstlisting}[stepnumber=0,frame=]{}
-#define IS_FILE_DIR(x) (((x) & S_IFMT) & (S_IFDIR | S_IFREG))
-\end{lstlisting}
+\includecodesnip{listati/is_file_dir.h}
in cui prima si estraggono da \var{st\_mode} i bit relativi al tipo di file e
poi si effettua il confronto con la combinazione di tipi scelta.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct utimbuf {
- time_t actime; /* access time */
- time_t modtime; /* modification time */
-};
- \end{lstlisting}
+ \includestruct{listati/utimbuf.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{utimbuf}, usata da \func{utime} per modificare
alcune applicazioni per sostituire i file corrispondenti ai file standard
visti in \secref{sec:file_std_descr}: se ad esempio si chiude lo standard
input e si apre subito dopo un nuovo file questo diventerà il nuovo standard
-input (avrà cioè il file descriptor 0).
-
-Il nuovo file descriptor non è condiviso con nessun altro processo (torneremo
-sulla condivisione dei file, in genere accessibile dopo una \func{fork}, in
-\secref{sec:file_sharing}). Il nuovo file descriptor è impostato per restare
-aperto attraverso una \func{exec} (come accennato in \secref{sec:proc_exec}) e
-l'offset è impostato all'inizio del file.
-
-L'argomento \param{mode} specifica i permessi con cui il file viene
-eventualmente creato; i valori possibili sono gli stessi già visti in
-\secref{sec:file_perm_overview} e possono essere specificati come OR binario
-delle costanti descritte in \tabref{tab:file_bit_perm}. Questi permessi sono
-filtrati dal valore di \var{umask} (vedi \secref{sec:file_umask}) per il
-processo.
+input (avrà cioè il file descriptor 0). Il nuovo file descriptor non è
+condiviso con nessun altro processo (torneremo sulla condivisione dei file, in
+genere accessibile dopo una \func{fork}, in \secref{sec:file_sharing}) ed è
+impostato per restare aperto attraverso una \func{exec} (come accennato in
+\secref{sec:proc_exec}); l'offset è impostato all'inizio del file.
+
+L'argomento \param{mode} indica i permessi con cui il file viene creato; i
+valori possibili sono gli stessi già visti in \secref{sec:file_perm_overview}
+e possono essere specificati come OR binario delle costanti descritte in
+\tabref{tab:file_bit_perm}. Questi permessi sono filtrati dal valore di
+\var{umask} (vedi \secref{sec:file_umask}) per il processo.
La funzione prevede diverse opzioni, che vengono specificate usando vari bit
dell'argomento \param{flags}. Alcuni di questi bit vanno anche a costituire
campo \var{f\_flags} della struttura \struct{file} (al solito si veda lo schema
di \figref{fig:file_proc_file}). Essi sono divisi in tre categorie
principali:
-\begin{itemize}
+\begin{itemize*}
\item \textsl{i bit delle modalità di accesso}: specificano con quale modalità
si accederà al file: i valori possibili sono lettura, scrittura o
lettura/scrittura. Uno di questi bit deve essere sempre specificato quando
si apre un file. Vengono impostati alla chiamata da \func{open}, e possono
- essere riletti con una \func{fcntl} (fanno parte del \textit{file status
- flag}), ma non possono essere modificati.
+ essere riletti con \func{fcntl} (fanno parte del \textit{file status flag}),
+ ma non possono essere modificati.
\item \textsl{i bit delle modalità di apertura}: permettono di specificare
alcune delle caratteristiche del comportamento di \func{open} quando viene
eseguita. Hanno effetto solo al momento della chiamata della funzione e non
sono memorizzati né possono essere riletti.
\item \textsl{i bit delle modalità di operazione}: permettono di specificare
alcune caratteristiche del comportamento delle future operazioni sul file
- (come la \func{read} o la \func{write}). Anch'essi fanno parte del
- \textit{file status flag}. Il loro valore è impostato alla chiamata di
- \func{open}, ma possono essere riletti e modificati (insieme alle
- caratteristiche operative che controllano) con una \func{fcntl}.
-\end{itemize}
+ (come \func{read} o \func{write}). Anch'essi fan parte del \textit{file
+ status flag}. Il loro valore è impostato alla chiamata di \func{open}, ma
+ possono essere riletti e modificati (insieme alle caratteristiche operative
+ che controllano) con una \func{fcntl}.
+\end{itemize*}
-In \tabref{tab:file_open_flags} si sono riportate, ordinate e divise fra loro
+In \tabref{tab:file_open_flags} sono riportate, ordinate e divise fra loro
secondo le tre modalità appena elencate, le costanti mnemoniche associate a
-ciascuno di questi bit. Dette costanti possono essere combinate fra di loro
-con un OR aritmetico per costruire il valore (in forma di maschera binaria)
-dell'argomento \param{flags} da passare alla \func{open} per specificarne il
-comportamento. I due flag \const{O\_NOFOLLOW} e \const{O\_DIRECTORY} sono
-estensioni specifiche di Linux, e deve essere definita la macro
-\macro{\_GNU\_SOURCE} per poterli usare.
+ciascuno di questi bit. Dette costanti possono essere combinate fra loro con
+un OR aritmetico per costruire il valore (in forma di maschera binaria)
+dell'argomento \param{flags} da passare alla \func{open}. I due flag
+\const{O\_NOFOLLOW} e \const{O\_DIRECTORY} sono estensioni specifiche di
+Linux, e deve essere definita la macro \macro{\_GNU\_SOURCE} per poterli
+usare.
Nelle prime versioni di Unix i valori di \param{flag} specificabili per
\func{open} erano solo quelli relativi alle modalità di accesso del file. Per
Chiude il descrittore \param{fd}.
\bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
- ed in questo caso \var{errno} assumerà uno dei valori:
+ con \var{errno} che assume i valori:
\begin{errlist}
\item[\errcode{EBADF}] \param{fd} non è un descrittore valido.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
Come accennato in \secref{sec:file_file_size} con \func{lseek} è possibile
impostare la posizione corrente anche oltre la fine del file, e alla
-successiva scrittura il file sarà esteso. La chiamata non causa nessuna
-attività di input/output, si limita a modificare la posizione corrente nel
-kernel (cioè \var{f\_pos} in \param{file}, vedi \figref{fig:file_proc_file}).
-
-Dato che la funzione ritorna la nuova posizione, usando il valore zero per
-\param{offset} si può riottenere la posizione corrente nel file chiamando la
-funzione con \code{lseek(fd, 0, SEEK\_CUR)}.
+successiva scrittura il file sarà esteso. La chiamata non causa nessun accesso
+al file, si limita a modificare la posizione corrente (cioè il valore
+\var{f\_pos} in \param{file}, vedi \figref{fig:file_proc_file}). Dato che la
+funzione ritorna la nuova posizione, usando il valore zero per \param{offset}
+si può riottenere la posizione corrente nel file chiamando la funzione con
+\code{lseek(fd, 0, SEEK\_CUR)}.
Si tenga presente inoltre che usare \const{SEEK\_END} non assicura affatto che
la successiva scrittura avvenga alla fine del file, infatti se questo è stato
aperto anche da un altro processo che vi ha scritto, la fine del file può
essersi spostata, ma noi scriveremo alla posizione impostata in precedenza
-(questa è una potenziale sorgente di \textit{race condition}
-\index{race condition}, vedi \secref{sec:file_atomic}).
+(questa è una potenziale sorgente di
+\textit{race condition}\index{race condition}, vedi \secref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per
La funzione tenta di leggere \param{count} byte a partire dalla posizione
corrente nel file. Dopo la lettura la posizione sul file è spostata
automaticamente in avanti del numero di byte letti. Se \param{count} è zero la
-funzione restituisce zero senza nessun altro risultato.
-
-Si deve sempre tener presente che non è detto che la funzione \func{read}
-restituisca sempre il numero di byte richiesto, ci sono infatti varie ragioni
-per cui la funzione può restituire un numero di byte inferiore; questo è un
-comportamento normale, e non un errore, che bisogna sempre tenere presente.
+funzione restituisce zero senza nessun altro risultato. Si deve sempre tener
+presente che non è detto che la funzione \func{read} restituisca sempre il
+numero di byte richiesto, ci sono infatti varie ragioni per cui la funzione
+può restituire un numero di byte inferiore; questo è un comportamento normale,
+e non un errore, che bisogna sempre tenere presente.
La prima e più ovvia di queste ragioni è che si è chiesto di leggere più byte
di quanto il file ne contenga. In questo caso il file viene letto fino alla
sua fine, e la funzione ritorna regolarmente il numero di byte letti
-effettivamente.
-
-Raggiunta la fine del file, alla ripetizione di un'operazione di lettura,
-otterremmo il ritorno immediato di \func{read} con uno zero. La condizione di
-raggiungimento della fine del file non è un errore, e viene segnalata appunto
-da un valore di ritorno di \func{read} nullo. Ripetere ulteriormente la
-lettura non avrebbe nessun effetto se non quello di continuare a ricevere zero
-come valore di ritorno.
+effettivamente. Raggiunta la fine del file, alla ripetizione di un'operazione
+di lettura, otterremmo il ritorno immediato di \func{read} con uno zero. La
+condizione di raggiungimento della fine del file non è un errore, e viene
+segnalata appunto da un valore di ritorno di \func{read} nullo. Ripetere
+ulteriormente la lettura non avrebbe nessun effetto se non quello di
+continuare a ricevere zero come valore di ritorno.
Con i \textsl{file regolari} questa è l'unica situazione in cui si può avere
un numero di byte letti inferiore a quello richiesto, ma questo non è vero
Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un
socket\index{socket}, come vedremo in \secref{sec:sock_io_behav}), o per la
lettura da certi file di dispositivo, come le unità a nastro, che
-restituiscono sempre i dati ad un singolo blocco alla volta.
+restituiscono sempre i dati ad un singolo blocco alla volta.
In realtà anche le due condizioni segnalate dagli errori \errcode{EINTR} e
\errcode{EAGAIN} non sono errori. La prima si verifica quando la \func{read} è
bloccata in attesa di dati in ingresso e viene interrotta da un segnale; in
tal caso l'azione da intraprendere è quella di rieseguire la funzione.
-Torneremo in dettaglio sull'argomento in \secref{sec:sig_gen_beha}.
-
-La seconda si verifica quando il file è in modalità non bloccante (vedi
+Torneremo in dettaglio sull'argomento in \secref{sec:sig_gen_beha}. La
+seconda si verifica quando il file è in modalità non bloccante (vedi
\secref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione
-allora ritorna immediatamente con un errore \errcode{EAGAIN}\footnote{sotto
- BSD per questo errore viene usata la costante \errcode{EWOULDBLOCK}, in
- Linux, con le glibc, questa è sinonima di \errcode{EAGAIN}.} che indica
-soltanto che occorrerà provare a ripetere la lettura.
+allora ritorna immediatamente con un errore \errcode{EAGAIN}\footnote{BSD usa
+ per questo errore la costante \errcode{EWOULDBLOCK}, in Linux, con le
+ \acr{glibc}, questa è sinonima di \errcode{EAGAIN}.} che indica soltanto che
+occorrerà provare a ripetere la lettura.
La funzione \func{read} è una delle system call fondamentali, esistenti fin
dagli albori di Unix, ma nella seconda versione delle \textit{Single Unix
\end{prototype}
\noindent che però diventa accessibile solo con la definizione della macro:
\begin{verbatim}
- #define _XOPEN_SOURCE 500
+#define _XOPEN_SOURCE 500
\end{verbatim}
Questa funzione serve quando si vogliono leggere dati dal file senza
chiuso in lettura; in questo caso viene anche generato il segnale
\const{SIGPIPE}, se questo viene gestito (o bloccato o ignorato) la
funzione ritorna questo errore.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
- aver potuto scrivere qualsiasi dato.
- \item[\errcode{EAGAIN}] la funzione non aveva nessun dato da restituire e si
- era aperto il file in modalità \const{O\_NONBLOCK}.
+ \item[\errcode{EINTR}] si è stati interrotti da un segnale prima di aver
+ potuto scrivere qualsiasi dato.
+ \item[\errcode{EAGAIN}] ci si sarebbe bloccati, ma il file era aperto in
+ modalità \const{O\_NONBLOCK}.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{EIO}, \errval{EISDIR}, \errval{EBADF},
\errval{ENOSPC}, \errval{EINVAL} e \errval{EFAULT} ed eventuali altri errori
il processo viene eseguito per la prima volta e diminuito progressivamente ad
ogni interruzione del timer.
-Quando lo scheduler\index{scheduler} viene eseguito scandisce la coda dei
-processi in stato \textit{runnable} associando, sulla base del valore di
-\var{counter}, un peso a ciascun processo in attesa di esecuzione,\footnote{il
+Durante la sua esecuzione lo scheduler\index{scheduler} scandisce la coda dei
+processi in stato \textit{runnable} associando, in base al valore di
+\var{counter}, un peso ad ogni processo in attesa di esecuzione,\footnote{il
calcolo del peso in realtà è un po' più complicato, ad esempio nei sistemi
- multiprocessore viene favorito un processo che è eseguito sulla stessa CPU,
- e a parità del valore di \var{counter} viene favorito chi ha una priorità
- più elevata.} chi ha il peso più alto verrà posto in esecuzione, ed il
+ multiprocessore viene favorito un processo eseguito sulla stessa CPU, e a
+ parità del valore di \var{counter} viene favorito chi ha una priorità più
+ elevata.} chi ha il peso più alto verrà posto in esecuzione, ed il
precedente processo sarà spostato in fondo alla coda. Dato che ad ogni
interruzione del timer il valore di \var{counter} del processo corrente viene
diminuito, questo assicura che anche i processi con priorità più bassa
\item[\errcode{EINVAL}] il valore di \param{which} non è valido.
\end{errlist}}
\end{prototype}
-\noindent (in vecchie versioni può essere necessario includere anche
+\noindent nelle vecchie versioni può essere necessario includere anche
\file{<sys/time.h>}, questo non è più necessario con versioni recenti delle
-librerie, ma è comunque utile per portabilità).
+librerie, ma è comunque utile per portabilità.
-La funzione permette di leggere la priorità di un processo, di un gruppo di
-processi (vedi \secref{sec:sess_proc_group}) o di un utente, a seconda del
-valore di \param{which}, secondo la legenda di \tabref{tab:proc_getpriority},
-specificando un corrispondente valore per \param{who}; un valore nullo di
-quest'ultimo indica il processo, il gruppo di processi o l'utente correnti.
+La funzione permette, a seconda del valore di \param{which}, di leggere la
+priorità di un processo, di un gruppo di processi (vedi
+\secref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
+valore per \param{who}; un valore nullo di quest'ultimo indica il processo, il
+gruppo di processi o l'utente correnti.
\begin{table}[htb]
\centering
siano installate le patch di RTLinux, RTAI o Adeos, con i quali è possibile
ottenere un sistema effettivamente hard real-time. In tal caso infatti gli
interrupt vengono intercettati dall'interfaccia real-time (o nel caso di
- Adeos gestiti dalle code del nano-kernel), in modo da poterlo controllare
+ Adeos gestiti dalle code del nano-kernel), in modo da poterli controllare
direttamente qualora ci sia la necessità di avere un processo con priorità
più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
page fault\index{page fault} si possono avere ritardi non previsti. Se
non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di
esecuzione di qualunque processo.
-In ogni caso occorre usare le priorità assolute con molta attenzione: se si dà
-ad un processo una priorità assoluta e questo finisce in un loop infinito,
-nessun altro processo potrà essere eseguito, ed esso sarà mantenuto in
-esecuzione permanentemente assorbendo tutta la CPU e senza nessuna possibilità
-di riottenere l'accesso al sistema. Per questo motivo è sempre opportuno,
-quando si lavora con processi che usano priorità assolute, tenere attiva una
-shell cui si sia assegnata la massima priorità assoluta, in modo da poter
-essere comunque in grado di rientrare nel sistema.
+Occorre usare le priorità assolute con molta attenzione: se si dà ad un
+processo una priorità assoluta e questo finisce in un loop infinito, nessun
+altro processo potrà essere eseguito, ed esso sarà mantenuto in esecuzione
+permanentemente assorbendo tutta la CPU e senza nessuna possibilità di
+riottenere l'accesso al sistema. Per questo motivo è sempre opportuno, quando
+si lavora con processi che usano priorità assolute, tenere attiva una shell
+cui si sia assegnata la massima priorità assoluta, in modo da poter essere
+comunque in grado di rientrare nel sistema.
Quando c'è un processo con priorità assoluta lo scheduler\index{scheduler} lo
metterà in esecuzione prima di ogni processo normale. In caso di più processi
sarà eseguito per primo quello con priorità assoluta più alta. Quando ci sono
più processi con la stessa priorità assoluta questi vengono tenuti in una coda
e tocca al kernel decidere quale deve essere eseguito.
-
Il meccanismo con cui vengono gestiti questi processi dipende dalla politica
di scheduling che si è scelto; lo standard ne prevede due:
-\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
+\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}}
\item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito
fintanto che non cede volontariamente la CPU, si blocca, finisce o viene
interrotto da un processo a priorità più alta.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sched_param {
- int sched_priority;
-};
- \end{lstlisting}
+ \includestruct{listati/sched_param.c}
\end{minipage}
\normalsize
\caption{La struttura \structd{sched\_param}.}