\itindend{memory~mapping}
-
-
\subsection{I/O vettorizzato: \func{readv} e \func{writev}}
\label{sec:file_multiple_io}
(\texttt{\small 18--22}), quello di destinazione (\texttt{\small 23--27}) ed
infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer.
-
\begin{figure}[!htbp]
\footnotesize \centering
\begin{minipage}[c]{15cm}
byte disponibili da copiare (la funzione in questo caso non si blocca, a
differenza di quanto avverrebbe per una normale lettura). Un esempio di
realizzazione del comando \texttt{tee} usando questa funzione, ripreso da
-quello fornito nella pagina di manuale, è riportato in fig..
+quello fornito nella pagina di manuale e dall'esempio allegato al pacth
+originale, è riportato in fig.~\ref{fig:tee_example}. Il programma consente di
+copiare il contenuto dello standard input sullo standard output e su un file
+specificato come argomento, il codice completo si trova nel file
+\texttt{tee.c} dei sorgenti allegati alla guida.
+% TODO verificare funzionamento, su Ubuntu Feisty non va...
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/tee.c}
+ \end{minipage}
+ \normalsize
+ \caption{Esempio di codice che usa \func{tee} per copiare i dati dello
+ standard input sullo standard output e su un file.}
+ \label{fig:tee_example}
+\end{figure}
-Infine come nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}
-occorre sottolineare che benché si sia parlato finora di trasferimenti o copie
-di dati in realtà nella loro implementazione non è affatto detto che questi
-vengono effettivamente spostati o copiati, il kernel infatti realizza le
-\textit{pipe} come un insieme di puntatori\footnote{per essere precisi si
- tratta di un semplice buffer circolare, un buon articolo sul tema si trova
- su \href{http://lwn.net/Articles/118750/}
+La prima parte del programma (\texttt{\small 10--35}) si cura semplicemente di
+controllare (\texttt{\small 11--14}) che sia stato fornito almeno un argomento
+(il nome del file su cui scrivere), di aprirlo ({\small 15--19}) e che sia lo
+standard input (\texttt{\small 20--27}) che lo standard output (\texttt{\small
+ 28--35}) corripondano ad una \textit{pipe}.
+
+Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a
+\func{tee} che duplica il contenuto dello standard input sullo standard output
+(\texttt{\small 39}), questa parte è del tutto analoga ad una lettura ed
+infatti come nell'esempio di fig.~\ref{fig:splice_example} si controlla il
+valore di ritorno della funzione in \var{len}; se questo è nullo significa che
+non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se
+è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è
+dovuto ad una interruzione (\texttt{\small 42--44}) o si stampa un messaggio
+di errore e si esce negli altri casi (\texttt{\small 44--47}).
+
+Una volta completata la copia dei dati sullo standard output si possono
+estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di
+scrittura (\texttt{\small 50--58}) in cui si ripete una chiamata a
+\func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i
+\var{len} byte copiati in precedenza con \func{tee} (il funzionamento è
+identico all'analogo ciclo di scrittura del precedente esempio di
+fig.~\ref{fig:splice_example}).
+
+Infine una nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}:
+occorre sottolineare che benché finora si sia parlato di trasferimenti o copie
+di dati in realtà nella implementazione di queste system call non è affatto
+detto che i dati vengono effettivamente spostati o copiati, il kernel infatti
+realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere
+ precisi si tratta di un semplice buffer circolare, un buon articolo sul tema
+ si trova su \href{http://lwn.net/Articles/118750/}
{\texttt{http://lwn.net/Articles/118750/}}.} alle pagine di memoria interna
che contengono i dati, per questo una volta che i dati sono presenti nella
memoria del kernel tutto quello che viene fatto è creare i suddetti puntatori
-ed aumentare il numero di referenze, pertanto anche con \func{tee} non viene
-mai copiato nessun byte, vengono semplicemente copiati i puntatori.
-
-
-% TODO documentare le funzioni tee e splice
-% http://kerneltrap.org/node/6505 e http://lwn.net/Articles/178199/ e
-% http://lwn.net/Articles/179492/ e http://lwn.net/Articles/181169
-% e http://en.wikipedia.org/wiki/Splice_(system_call)
-
+ed aumentare il numero di referenze; questo significa che anche con \func{tee}
+non viene mai copiato nessun byte, vengono semplicemente copiati i puntatori.
verranno usati i file, possono necessitare di effettuare delle ottimizzazioni
specifiche, relative alle proprie modalità di I/O sugli stessi. Tratteremo in
questa sezione una serie funzioni che consentono ai programmi di ottimizzare
-il loro accesso ai dati dei file.
+il loro accesso ai dati dei file e controllare la gestione del relativo
+\textit{caching}.
+
-% TODO documentare \func{madvise}
-% TODO documentare \func{mincore}
% TODO documentare \func{posix\_fadvise}
+% TODO documentare \func{readahead}
% vedi http://insights.oetiker.ch/linux/fadvise.html
% questo tread? http://www.ussg.iu.edu/hypermail/linux/kernel/0703.1/0032.html
output sul file.
In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le \textit{race condition} \itindex{race~condition}, attraverso una
+evitare le \itindex{race~condition} \textit{race condition}, attraverso una
serie di funzioni che permettono di bloccare l'accesso al file da parte di
altri processi, così da evitare le sovrapposizioni, e garantire la atomicità
delle operazioni di scrittura.
\include{session}
\include{fileadv}
\include{ipc}
+\include{thread}
% Commentare sotto se si genera la prima parte
\part{Programmazione di rete}
--- /dev/null
+#define _GNU_SOURCE
+#include <fcntl.h> /* file control functions */
+...
+int main(int argc, char *argv[])
+{
+ size_t size = 4096;
+ int fd, len, nwrite;
+ struct stat fdata;
+ ...
+ /* check argument, open destination file and check stdin and stdout */
+ if ((argc - optind) != 1) { /* There must be one argument */
+ printf("Wrong number of arguments %d\n", argc - optind);
+ usage();
+ }
+ fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ printf("opening file %s falied: %s", argv[1], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (fstat(STDIN_FILENO, &fdata) < 0) {
+ perror("cannot stat stdin");
+ exit(EXIT_FAILURE);
+ }
+ if (!S_ISFIFO(fdata.st_mode)) {
+ fprintf(stderr, "stdin must be a pipe\n");
+ exit(EXIT_FAILURE);
+ }
+ if (fstat(STDOUT_FILENO, &fdata) < 0) {
+ perror("cannot stat stdout");
+ exit(EXIT_FAILURE);
+ }
+ if (!S_ISFIFO(fdata.st_mode)) {
+ fprintf(stderr, "stdout must be a pipe\n");
+ exit(EXIT_FAILURE);
+ }
+ /* tee loop */
+ while (1) {
+ /* copy stdin to stdout */
+ len = tee(STDIN_FILENO, STDOUT_FILENO, size, SPLICE_F_NONBLOCK);
+ if (len == 0) break;
+ if (len < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ } else {
+ perror("error on tee stdin to stdout");
+ exit(EXIT_FAILURE);
+ }
+ }
+ /* write data to the file using splice */
+ while (len > 0) {
+ nwrite = splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
+ if (nwrite < 0) {
+ perror("error on splice stdin to file");
+ break;
+ }
+ len -= nwrite;
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
\itindend{memory~locking}
+% TODO documentare \func{madvise}
+% TODO documentare \func{mincore}
+
\index{memoria~virtuale|)}
% \subsection{Gestione avanzata dell'allocazione della memoria}
% \label{sec:proc_mem_malloc_custom}
% TODO: trattare le funzionalità avanzate di \func{malloc}
+% TODO: trattare \func{memalign}
size_t size = 4096;
int fd;
int len, nwrite;
- struct stat sb;
+ struct stat fdata;
/*
* Input section: decode command line parameters
* Use getopt function
/*
* Main body
*/
- if ((argc - optind) != 1) { /* There must two argument */
+ if ((argc - optind) != 1) { /* There must be one argument */
printf("Wrong number of arguments %d\n", argc - optind);
usage();
}
- /* open destination file */
+ /* open destination file and check stdin and stdout */
fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd == -1) {
printf("cannot open destination file %s, %s", argv[1],
strerror(errno));
exit(EXIT_FAILURE);
}
-
-
- if (fstat(STDIN_FILENO, &sb) < 0) {
+ if (fstat(STDIN_FILENO, &fdata) < 0) {
perror("stat");
exit(EXIT_FAILURE);
}
- if (!S_ISFIFO(sb.st_mode)) {
+ if (!S_ISFIFO(fdata.st_mode)) {
fprintf(stderr, "stdin must be a pipe\n");
exit(EXIT_FAILURE);
}
- if (fstat(STDOUT_FILENO, &sb) < 0) {
+ if (fstat(STDOUT_FILENO, &fdata) < 0) {
perror("stat");
exit(EXIT_FAILURE);
}
- if (!S_ISFIFO(sb.st_mode)) {
+ if (!S_ISFIFO(fdata.st_mode)) {
fprintf(stderr, "stdout must be a pipe\n");
exit(EXIT_FAILURE);
}
-
/* tee loop */
- //debug("Size %d\n", size);
while (1) {
/* copy stdin to stdout */
len = tee(STDIN_FILENO, STDOUT_FILENO, size, SPLICE_F_NONBLOCK);
+ if (len == 0) break;
if (len < 0) {
if (errno == EAGAIN) {
continue;
perror("error on tee stdin to stdout");
exit(EXIT_FAILURE);
}
- } else {
- if (len == 0) break;
- }
- fprintf(stderr, "Copied %d byte\n", len);
+ }
+ fprintf(stderr, "Copied %d byte\n", len); /* debug (use stderr!) */
/* write data to the file using splice */
while (len > 0) {
nwrite = splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
void usage(void) {
printf("Program tee: duplicate stdin to stdout and a file\n");
printf("Usage:\n");
- printf(" splicecp [-h] [-s N] filename\n");
+ printf(" tee [-h] [-s N] filename\n");
printf(" -h print this help\n");
printf(" -s N set a buffer size of N bytes \n");
exit(1);
--- /dev/null
+%% thread.tex
+%%
+%% Copyright (C) 2007 Simone Piccardi. Permission is granted to
+%% copy, distribute and/or modify this document under the terms of the GNU Free
+%% Documentation License, Version 1.1 or any later version published by the
+%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
+%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
+
+\chapter{I thread}
+\label{cha:threads}
+
+Tratteremo in questo capitolo un modello di programmazione multitasking,
+quello dei \textit{thread}, alternativo al modello classico dei processi,
+tipico di Unix. Ne esaminiremo le caratteristiche, vantaggi e svantaggi, e le
+diverse realizzazioni che sono disponibili per Linux; nella seconda parte
+tratteremo in dettaglio quella che è l'implementazione principale, che fa
+riferimento all'interfaccia standardizzata da POSIX.1e.
+
+
+\section{Introduzione ai \textit{thread}}
+\label{sec:thread_intro}
+
+Questa prima sezione costituisce una introduzione ai \textit{thread} e
+tratterà i concetti principali del relativo modello di programmazione,
+esamineremo anche queli modelli sono disponibili per Linux, dando una breve
+panoramica sulle implementazioni alternative.
+
+
+\subsection{Una panoramica}
+\label{sec:thread_overview}
+
+% riferimenti
+% http://vergil.chemistry.gatech.edu/resources/programming/threads.html
+% http://math.arizona.edu/~swig/documentation/pthreads/
+% http://www.humanfactor.com/pthreads/
+
+
+\subsection{I \textit{thread} e Linux}
+\label{sec:linux_thread}
+
+\subsection{Implementazioni alternative}
+\label{sec:thread_other}
+
+
+
+
+% http://www.gnu.org/software/pth/
+
+
+\section{Posix \textit{thread}}
+\label{sec:thread_intro}
+
+
+Tratteremo in questa sezione l'interfaccia di programmazione con i
+\textit{thread} standardizzata dallo standard POSIX 1.c, che è quella che è
+stata seguita anche dalle varie implementazioni dei \textit{thread} realizzate
+su Linux, ed in particolare dalla \textit{Native Thread Posix Library} che è
+stata integrata con i kernel della serie 2.6 e che fa parte a pieno titolo
+delle \acr{glibc}.
+
+
+\subsection{Una panoramica}
+\label{sec:pthread_overview}
+
+
+\subsection{La gestione dei \textit{thread}}
+\label{sec:pthread_management}
+
+
+\subsection{I \textit{mutex}}
+\label{sec:pthread_mutex}
+
+
+\subsection{Le variabili di condizione}
+\label{sec:pthread_cond}
+
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End: