sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
+
+\subsection{Il file locking in Linux}
+\label{sec:file_linux_file_lock}
+
+L'implementazione del \textit{file locking} in Linux, benché perfettamente
+funzionante, resta una sovrapposizione di diverse interfacce, risultante in
+una complessità
+
+
+
\subsection{L'\textit{advisory locking}}
\label{sec:file_record_locking}
\end{prototype}
Il comportamento della funzione è specificato dal valore dell'argomento
-\param{operation}, da passare come maschera binaria dei valori riportati in
-\tabref{tab:file_flock_operation}.
+\param{operation}, da passare come maschera binaria dei valori riportati in
+\tabref{tab:file_flock_operation}. Quando si chiude un file i lock esistenti
+su di esso vengono sempre cancellati.
+
\begin{table}[htb]
\centering
\label{tab:file_flock_operation}
\end{table}
-
-Con \func{flock} il blocco è associato direttamente al file (cioè rispetto
-allo schema di \secref{sec:file_fd} fa riferimento all'inode e non al file
-descriptor); pertanto sia \func{dup} che \func{fork} non creano altre istanze
-del blocco ma piuttosto degli ulteriori riferimenti allo stesso \textit{file
- lock}.
-
-La funzione blocca direttamente il file (cioè rispetto allo schema di
-\secref{fig:file_stat_struct} fa riferimento alla struttura \var{file}, non al
-file descriptor). Pertanto sia \func{dup} che \func{fork} non creano ulteriori
-istanze di un \textit{file lock} quanto piuttosto degli ulteriori riferimenti
-allo stesso \textit{file lock}. Questo comporta che un lock può essere rimosso
-su uno qualunque dei file descriptor che fanno riferimento allo stesso file,
-ed esso .
+La funzione esegue il blocco direttamente il file (cioè rispetto allo schema
+di \secref{fig:file_stat_struct} il blocco è mantenuto in riferimento alla
+struttura \var{file}, non al file descriptor). Pertanto sia \func{dup} che
+\func{fork} non creano ulteriori istanze di un \textit{file lock} quanto
+piuttosto degli ulteriori riferimenti allo stesso. Questo comporta che un
+\textit{file lock} può essere rimosso su uno qualunque dei file descriptor che
+fanno riferimento allo stesso file: quindi se si toglie il blocco in un
+processo figlio o su un file descriptor duplicato, questo sarà cancellato
+rispettivamente anche nel processo padre e sul file descriptor originario.
La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
}
\end{prototype}
+Si tenga presente che \func{flock} non è in grado di funzionare per i file
+manetenuti su NFS, in questo caso, se si ha la necessità di eseguire il
+\textit{file locking}, occorre usare l'interfaccia basata su \func{fcntl} che
+può funzionare anche attraverso NFS, a condizione che sia il client che il
+server supportino questa funzionalità.
+
+
+La standardizzatione operata con POSIX.1 ha adottato le API per il
+\textit{file locking} originarie di System V, basate sulla funzione
+
Al contrario di \func{flock} con \func{fcntl} è possibile bloccare anche solo
-delle sezioni di un file. La funzione prende come argomento
+delle sezioni di un file. La funzione prende come argomento una struttura
+\var{flock} la cui definizione è riportata in \figref{fig:struct_flock}.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct struct {
+struct flock {
short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
off_t l_start; /* Offset where the lock begins. */
-
-Si tenga conto che \func{flock} non è in grado di eseguire il \textit{file
- locking} su NFS, se si ha questa necessità occorre usare \func{fcntl} che
-funziona anche attraverso NFS, posto che il server supporti il \textit{file
- locking}.
-
\subsection{Il \textit{mandatory locking}}
\label{sec:file_mand_locking}
\begin{figure}[htb]
\centering
- \includegraphics[width=7cm]{img/link_loop}
+ \includegraphics[width=9cm]{img/link_loop}
\caption{Esempio di loop nel filesystem creato con un link simbolico.}
\label{fig:file_link_loop}
\end{figure}
\footnotesize
\centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
struct stat {
dev_t st_dev; /* device */
ino_t st_ino; /* inode */
\label{fig:file_stat_struct}
\end{figure}
-Si noti come i vari membri della struttura siano specificati come tipi nativi
-del sistema (di quelli definiti in \tabref{tab:xxx_sys_types}, e dichiarati in
-\file{sys/types.h}).
+Si noti come i vari membri della struttura siano specificati come tipi
+primitivi del sistema (di quelli definiti in
+\tabref{tab:intro_primitive_types}, e dichiarati in \file{sys/types.h}).
\subsection{I tipi di file}
\end{errlist}}
\end{prototype}
-La struttura \var{utimebuf} usata da \func{utime} è definita come:
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+La funzione prende come argomento \param{times} una struttura \var{utimebuf},
+la cui definizione è riportata in \figref{fig:struct_utimebuf}, con la quale
+si possono specificare i nuovi valori che si vogliono impostare per tempi.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
struct utimbuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
};
-\end{lstlisting}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \type{utimbuf}, usata da \func{utime} per modificare i
+ tempi dei file.}
+ \label{fig:struct_utimebuf}
+\end{figure}
L'effetto della funzione e i privilegi necessari per eseguirla dipendono da
cosa è l'argomento \param{times}; se è \macro{NULL} la funzione imposta il
volte che si modifica l'inode (quindi anche alla chiamata di \func{utime}).
Questo serve anche come misura di sicurezza per evitare che si possa
modificare un file nascondendo completamente le proprie tracce. In realtà la
-cosa resta possibile, se si è in grado di accedere al device, scrivendo
-direttamente sul disco senza passare attraverso il filesystem, ma ovviamente
-in questo modo la cosa è molto più complicata da realizzare.
+cosa resta possibile, se si è in grado di accedere al file di dispositivo,
+scrivendo direttamente sul disco senza passare attraverso il filesystem, ma
+ovviamente in questo modo la cosa è molto più complicata da realizzare.
\textbf{Standard} & \textbf{Contenuto} \\
\hline
\hline
- \texttt{stdio.h} & I/O bufferizzato in standard ANSI C.\\
- \texttt{stdlib.h} & definizioni della libreria standard.\\
- \texttt{...} & Da completare.\\
+ \file{assert.h}& Verifica le asserzioni fatte in un programma.\\
+ \file{cpio.h} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{} & .\\
+ \file{stdio.h} & I/O bufferizzato in standard ANSI C.\\
+ \file{stdlib.h}& definizioni della libreria standard.\\
\hline
\end{tabular}
\caption{Elenco dei vari file di include definiti dallo standard POSIX.}
\end{table}
-
In realtà \acr{glibc} ed i relativi header file definiscono un insieme di
funzionalità in cui sono incluse come sottoinsieme anche quelle previste dallo
standard ANSI C. È possibile ottenere una conformità stretta allo standard
usare le varie estensioni al linguaggio e al preprocessore da esso supportate.
+\subsection{I tipi di dati primitivi}
+\label{sec:intro_data_types}
+
+Uno dei problemi di portabilità del codice più comune è quello dei tipi di
+dati utilizzati nei programmi, che spesso variano da sistema a sistema, o
+anche da una architettura ad un altra (ad esempio passando da macchine con
+processori 32 bit a 64).
+
+Storicamente alcuni tipi di dati definiti dallo standard ANSI C sono sempre
+stati associati ad alcune variabili nei sistemi Unix, ad esempio la posizione
+corrente all'interno di un file è sempre stato associato ad un intero a 32
+bit, mentre il numero di dispositivo è sempre stato associato ad un intero a
+16 bit. Tutto questo ovviamente costituisce un incubo per la portabilità tutte
+le volte che, con l'evolversi delle piattaforme hardware, alcuni di questi
+tipi si sono rivelati inadeguati, e se ne è dovuto cambiare la dimensione.
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Tipo} & \textbf{Contenuto} \\
+ \hline
+ \hline
+ \type{caddr\_t} & core address.\\
+ \type{clock\_t} & contatore del tempo di sistema.\\
+ \type{dev\_t} & Numero di dispositivo.\\
+ \type{gid\_t} & Identificatore di un gruppo.\\
+ \type{ino\_t} & Numero di \textit{inode}.\\
+ \type{key\_t} & Chiave per il System V IPC.\\
+ \type{loff\_t} & Posizione corrente in un file.\\
+ \type{mode\_t} & Attributi di un file.\\
+ \type{nlink\_t} & Contatore dei link su un file.\\
+ \type{off\_t} & Posizione corrente in un file.\\
+ \type{pid\_t} & Identificatore di un processo.\\
+ \type{rlim\_t} & Limite sulle risorse.\\
+ \type{sigset\_t}& Insieme di segnali.\\
+ \type{ssize\_t} & Dimensione di un oggetto.\\
+ \type{ssize\_t} & Dimensione in numero byte ritornata dalle funzioni.\\
+ \type{ptrdiff\_t}& Differenza fra due puntatori.\\
+ \type{time\_t} & Numero di secondi (in tempo di calendario).\\
+ \type{uid\_t} & Identificatore di un utente.\\
+ \hline
+ \end{tabular}
+ \caption{Elenco dei tipi primitivi, definiti in \file{sys/types.h}.}
+ \label{tab:intro_primitive_types}
+\end{table}
+
+Per questo motivo tutte le funzioni di libreria di solito non fanno
+riferimento ai tipi standard del linguaggio C, ma ad una serie di \textsl{tipi
+ primitivi}, riportati in \tabref{tab:intro_primitive_types}, caratteristici
+di ogni sistema, definiti nell'header file \file{sys/types.h}, che associano i
+tipi utilizzati dalle funzioni di sistema ai tipi elementari supportati dal
+compilatore C.
+
+
+
\subsection{Lo standard IEEE -- POSIX}
\label{sec:intro_posix}
La shell ad esempio ne usa molte per il suo funzionamento (come \var{PATH} per
la ricerca dei comandi, o \cmd{IFS} per la scansione degli argomenti), e
-alcune di esse (come \var{HOME}, \var{USER}, etc.) sono definite al login. In
-genere è cura dell'amministratore definire le opportune variabili di ambiente
-in uno script di avvio. Alcune servono poi come riferimento generico per molti
-programmi (come \var{EDITOR} che indica l'editor preferito da invocare in caso
-di necessità).
+alcune di esse (come \var{HOME}, \var{USER}, etc.) sono definite al login (per
+i dettagli si veda \secref{sec:sess_login}). In genere è cura
+dell'amministratore definire le opportune variabili di ambiente in uno script
+di avvio. Alcune servono poi come riferimento generico per molti programmi
+(come \var{EDITOR} che indica l'editor preferito da invocare in caso di
+necessità).
Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più
comuni), come riportato in \tabref{tab:proc_env_var}. GNU/Linux le supporta
\begin{table}[htb]
\centering
+ \footnotesize
\begin{tabular}[c]{|l|c|c|c|p{7cm}|}
\hline
\textbf{Variabile} & \textbf{POSIX} & \textbf{XPG3}
\begin{table}[htb]
\centering
+ \footnotesize
\begin{tabular}[c]{|l|c|c|c|c|c|c|}
\hline
\textbf{Funzione} & \textbf{ANSI C} & \textbf{POSIX.1} & \textbf{XPG3} &
nel caso di Linux non si tratta di un vero hard real-time, in quanto in
presenza di eventuali interrupt il kernel interrompe l'esecuzione di un
processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si
- siano installate le patch di RTLinux o RTAI, con i quali è possibile
+ 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, e gestiti
+ interrupt vengono intercettati dall'interfaccia real-time (o nel caso di
+ Adeos gestiti dalle code del nano-kernel), in modo da poterlo 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
processi con la stessa priorità assoluta questi vengono tenuti in una coda
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{3cm}\desclabelstyle{\nextlinelabel}}
-\item[\textit{FIFO}] il processo viene eseguito fintanto che non cede
- volontariamente la CPU, si blocca, finisce o viene interrotto da un processo
- a priorità più alta.
-\item[\textit{Round Robin}] ciascun processo viene eseguito a turno per un
- certo periodo di tempo (una \textit{time slice}). Solo i processi con la
- stessa priorità ed in stato \textit{runnable} entrano nel circolo.
+\begin{basedescript}{\desclabelwidth{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.
+\item[\textit{RR}] \textit{Round Robin}. Ciascun processo viene eseguito a
+ turno per un certo periodo di tempo (una \textit{time slice}). Solo i
+ processi con la stessa priorità ed in stato \textit{runnable} entrano nel
+ circolo.
\end{basedescript}
La funzione per impostare le politiche di scheduling (sia real-time che