From fc2954a94ffab07871f49e2432d5223f55840fbf Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 18 Aug 2007 17:00:31 +0000 Subject: [PATCH] Finito con {{{tee}}}, spostati un po' di TODO, messo il placeholder per il capitolo sui ''thread'' --- fileadv.tex | 78 +++++++++++++++++++++++++++++++--------------- gapil.tex | 1 + listati/tee.c | 60 ++++++++++++++++++++++++++++++++++++ process.tex | 4 +++ sources/tee.c | 27 +++++++--------- thread.tex | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 215 insertions(+), 40 deletions(-) create mode 100644 listati/tee.c create mode 100644 thread.tex diff --git a/fileadv.tex b/fileadv.tex index 797ecfb..206fb8e 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -2730,8 +2730,6 @@ mappatura che gi \itindend{memory~mapping} - - \subsection{I/O vettorizzato: \func{readv} e \func{writev}} \label{sec:file_multiple_io} @@ -3138,7 +3136,6 @@ file destinazione. Il passo successivo (\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} @@ -3293,29 +3290,61 @@ all'altra (o $-1$ in caso di errore), un valore nullo indica che non ci sono 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. @@ -3335,12 +3364,13 @@ specifiche dei singoli programmi, che avendo una conoscenza diretta di come 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 @@ -3378,7 +3408,7 @@ in cui diversi processi scrivono, mescolando in maniera imprevedibile il loro 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. diff --git a/gapil.tex b/gapil.tex index 4d87c7d..3595858 100644 --- a/gapil.tex +++ b/gapil.tex @@ -156,6 +156,7 @@ \include{session} \include{fileadv} \include{ipc} +\include{thread} % Commentare sotto se si genera la prima parte \part{Programmazione di rete} diff --git a/listati/tee.c b/listati/tee.c new file mode 100644 index 0000000..51df9f6 --- /dev/null +++ b/listati/tee.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include /* 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); +} diff --git a/process.tex b/process.tex index a0e32df..b025b2b 100644 --- a/process.tex +++ b/process.tex @@ -917,6 +917,9 @@ ci si scrive sopra. \itindend{memory~locking} +% TODO documentare \func{madvise} +% TODO documentare \func{mincore} + \index{memoria~virtuale|)} @@ -924,6 +927,7 @@ ci si scrive sopra. % \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} diff --git a/sources/tee.c b/sources/tee.c index 18f01a2..559c949 100644 --- a/sources/tee.c +++ b/sources/tee.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) size_t size = 4096; int fd; int len, nwrite; - struct stat sb; + struct stat fdata; /* * Input section: decode command line parameters * Use getopt function @@ -85,41 +85,38 @@ int main(int argc, char *argv[]) /* * 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; @@ -127,10 +124,8 @@ int main(int argc, char *argv[]) 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); @@ -151,7 +146,7 @@ int main(int argc, char *argv[]) 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); diff --git a/thread.tex b/thread.tex new file mode 100644 index 0000000..88d25ac --- /dev/null +++ b/thread.tex @@ -0,0 +1,85 @@ +%% 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: -- 2.30.2