X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=458c8fac4b4fd688bfae67ecae5a14bd83421b3e;hp=e22736f329cba925ff4f1fece327943831702bd0;hb=e6ff0c2ef7388e665c6674c1752cdce21972c1eb;hpb=b3593007c4edd76ecbf7386967c1b25d27eed828 diff --git a/ipc.tex b/ipc.tex index e22736f..458c8fa 100644 --- a/ipc.tex +++ b/ipc.tex @@ -74,6 +74,9 @@ illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due capi della pipe, associati a ciascun file descriptor, con le frecce che indicano la direzione del flusso dei dati. +% TODO: la dimensione è cambiata a 64k (vedi man 7 pipe) e può essere +% modificata con F_SETPIPE_SZ dal 2.6.35 (vedi fcntl) + \begin{figure}[!htb] \centering \includegraphics[height=5cm]{img/pipe} @@ -82,7 +85,7 @@ indicano la direzione del flusso dei dati. \end{figure} Chiaramente creare una pipe all'interno di un singolo processo non serve a -niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_sharing} +niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_shared_access} riguardo al comportamento dei file descriptor nei processi figli, è immediato capire come una pipe possa diventare un meccanismo di intercomunicazione. Un processo figlio infatti condivide gli stessi file descriptor del padre, @@ -184,11 +187,10 @@ Il programma ci servirà anche come esempio dell'uso delle funzioni di duplicazione dei file descriptor che abbiamo trattato in sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste funzioni infatti che è possibile dirottare gli stream standard dei processi -(che abbiamo visto in sez.~\ref{sec:file_std_descr} e -sez.~\ref{sec:file_std_stream}) sulla pipe. In -fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma, -il cui codice completo è disponibile nel file \file{BarCodePage.c} che si -trova nella directory dei sorgenti. +(che abbiamo visto in tab.~\ref{tab:file_std_files} e +sez.~\ref{sec:file_stream}) sulla pipe. In fig.~\ref{fig:ipc_barcodepage_code} +abbiamo riportato il corpo del programma, il cui codice completo è disponibile +nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti. \begin{figure}[!htbp] \footnotesize \centering @@ -302,9 +304,9 @@ che sarà aperto in sola lettura (e quindi associato allo standard output del programma indicato) in caso si sia indicato \code{"r"}, o in sola scrittura (e quindi associato allo standard input) in caso di \code{"w"}. -Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file -stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad -una pipe e non ad un file, e viene sempre aperto in modalità +Lo \textit{stream} restituito da \func{popen} è identico a tutti gli effetti +ai \textit{file stream} visti in sez.~\ref{sec:files_std_interface}, anche se +è collegato ad una pipe e non ad un file, e viene sempre aperto in modalità \textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove funzioni, \funcd{pclose}, il cui prototipo è: @@ -431,9 +433,10 @@ quello illustrato per le pipe in sez.~\ref{sec:ipc_pipes}. Abbiamo già visto in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e \func{mkfifo} che permettono di creare una fifo; per utilizzarne una un -processo non avrà che da aprire il relativo file speciale o in lettura o -scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà -leggere, nel secondo al capo di ingresso, e dovrà scrivere. +processo non avrà che da aprire il relativo \index{file!speciali} file +speciale o in lettura o scrittura; nel primo caso sarà collegato al capo di +uscita della fifo, e dovrà leggere, nel secondo al capo di ingresso, e dovrà +scrivere. Il kernel crea una singola pipe per ciascuna fifo che sia stata aperta, che può essere acceduta contemporaneamente da più processi, sia in lettura che in @@ -727,20 +730,20 @@ dei socket in cap.~\ref{cha:socket_intro},\footnote{si tratta comunque di oggetti di comunicazione che, come le pipe, sono utilizzati attraverso dei file descriptor.} nell'ambito dell'interfaccia generale che essi forniscono per la programmazione di rete; e vedremo anche -(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali -(di tipo socket, analoghi a quello associati alle fifo) cui si accede però -attraverso quella medesima interfaccia; vale però la pena esaminare qui una -modalità di uso dei socket locali\footnote{la funzione \func{socketpair} è - stata introdotta in BSD4.4, ma è supportata in genere da qualunque sistema - che fornisca l'interfaccia dei socket.} che li rende sostanzialmente -identici ad una pipe bidirezionale. +(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei +\index{file!speciali} file speciali (di tipo socket, analoghi a quello +associati alle fifo) cui si accede però attraverso quella medesima +interfaccia; vale però la pena esaminare qui una modalità di uso dei socket +locali\footnote{la funzione \func{socketpair} è stata introdotta in BSD4.4, ma + è supportata in genere da qualunque sistema che fornisca l'interfaccia dei + socket.} che li rende sostanzialmente identici ad una pipe bidirezionale. La funzione \funcd{socketpair} infatti consente di creare una coppia di file descriptor connessi fra di loro (tramite un socket, appunto), senza dover -ricorrere ad un file speciale sul filesystem, i descrittori sono del tutto -analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, con la sola -differenza è che in questo caso il flusso dei dati può essere effettuato in -entrambe le direzioni. Il prototipo della funzione è: +ricorrere ad un \index{file!speciali} file speciale sul filesystem, i +descrittori sono del tutto analoghi a quelli che si avrebbero con una chiamata +a \func{pipe}, con la sola differenza è che in questo caso il flusso dei dati +può essere effettuato in entrambe le direzioni. Il prototipo della funzione è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/socket.h} @@ -1222,7 +1225,7 @@ cui queste strutture vengono mantenute dal kernel.\footnote{lo schema \label{fig:ipc_msqid_ds} \end{figure} -A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui +A ciascuna coda è associata una struttura \struct{msqid\_ds}, la cui definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il kernel mantiene le principali informazioni riguardo lo stato corrente della coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x, @@ -2064,6 +2067,10 @@ vengono effettuate con la funzione \funcd{semop}, il cui prototipo è: } \end{functions} + +%TODO manca semtimedop, trattare qui, referenziata in +%sez.~\ref{sec:sig_gen_beha}. + La funzione permette di eseguire operazioni multiple sui singoli semafori di un insieme. La funzione richiede come primo argomento l'identificatore \param{semid} dell'insieme su cui si vuole operare. Il numero di operazioni da @@ -2167,7 +2174,7 @@ Dato che, come già accennato in precedenza, in caso di uscita inaspettata i semafori possono restare occupati, abbiamo visto come \func{semop} permetta di attivare un meccanismo di ripristino attraverso l'uso del flag \const{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura -\struct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso +\kstruct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso ha modificato; all'uscita i semafori modificati vengono ripristinati, e le strutture disallocate. Per mantenere coerente il comportamento queste strutture non vengono ereditate attraverso una \func{fork} (altrimenti si @@ -2193,7 +2200,7 @@ Alla creazione di un nuovo insieme viene allocata una nuova strutture \struct{semid\_ds} ed il relativo vettore di strutture \struct{sem}. Quando si richiede una operazione viene anzitutto verificato che tutte le operazioni possono avere successo; se una di esse comporta il blocco del processo il -kernel crea una struttura \struct{sem\_queue} che viene aggiunta in fondo alla +kernel crea una struttura \kstruct{sem\_queue} che viene aggiunta in fondo alla coda di attesa associata a ciascun insieme di semafori\footnote{che viene referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} di \struct{semid\_ds}.}. @@ -2208,23 +2215,25 @@ Se invece tutte le operazioni possono avere successo queste vengono eseguite immediatamente, dopo di che il kernel esegue una scansione della coda di attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle operazioni sospese in precedenza può essere eseguita, nel qual caso la -struttura \struct{sem\_queue} viene rimossa e lo stato del processo associato +struttura \kstruct{sem\_queue} viene rimossa e lo stato del processo associato all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto viene ripetuto fin quando non ci sono più operazioni eseguibili o si è svuotata la coda. Per gestire il meccanismo del ripristino tutte le volte che per un'operazione si è specificato il flag \const{SEM\_UNDO} viene mantenuta -per ciascun insieme di semafori una apposita struttura \struct{sem\_undo} che +per ciascun insieme di semafori una apposita struttura \kstruct{sem\_undo} che contiene (nel vettore puntato dal campo \var{semadj}) un valore di aggiustamento per ogni semaforo cui viene sommato l'opposto del valore usato per l'operazione. +%TODO verificare queste strutture \kstruct{sem\_queue} e \kstruct{sem\_undo} + Queste strutture sono mantenute in due liste,\footnote{rispettivamente attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata all'insieme di cui fa parte il semaforo, che viene usata per invalidare le strutture se questo viene cancellato o per azzerarle se si è eseguita una operazione con \func{semctl}; l'altra associata al processo che ha eseguito l'operazione;\footnote{attraverso il campo \var{semundo} di - \struct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un + \kstruct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un processo termina, la lista ad esso associata viene scandita e le operazioni applicate al semaforo. Siccome un processo può accumulare delle richieste di ripristino per semafori differenti chiamate attraverso diverse chiamate a @@ -2832,12 +2841,12 @@ condivisa (la funzione si bloccherà automaticamente se qualche client sta leggendo), poi (\texttt{\small 44}) si cancellano i valori precedentemente immagazzinati nella memoria condivisa con \func{memset}, e si esegue (\texttt{\small 45}) un nuovo calcolo degli stessi utilizzando la funzione -\func{DirScan}; infine (\texttt{\small 46}) si sblocca il mutex con +\myfunc{dir\_scan}; infine (\texttt{\small 46}) si sblocca il mutex con \func{MutexUnlock}, e si attende (\texttt{\small 47}) per il periodo di tempo specificato a riga di comando con l'opzione \code{-p} con una \func{sleep}. Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si -sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e +sia usata ancora una volta la funzione \myfunc{dir\_scan}, già utilizzata (e descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di effettuare la scansione delle voci della directory, chiamando per ciascuna di esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari. @@ -2849,10 +2858,10 @@ ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari contatori nella memoria condivisa, cui accede grazie alla \index{variabili!globali} variabile globale \var{shmptr}. -Dato che la funzione è chiamata da \func{DirScan}, si è all'interno del ciclo -principale del programma, con un mutex acquisito, perciò non è necessario -effettuare nessun controllo e si può accedere direttamente alla memoria -condivisa usando \var{shmptr} per riempire i campi della struttura +Dato che la funzione è chiamata da \myfunc{dir\_scan}, si è all'interno del +ciclo principale del programma, con un mutex acquisito, perciò non è +necessario effettuare nessun controllo e si può accedere direttamente alla +memoria condivisa usando \var{shmptr} per riempire i campi della struttura \struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni dei file ed il loro numero, poi, utilizzando le macro di tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce @@ -3050,7 +3059,7 @@ La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare dei \textsl{file di lock} (per i quali esiste anche una opportuna directory, \file{/var/lock}, nel filesystem standard). Per questo si usa la caratteristica della funzione \func{open} (illustrata in -sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo +sez.~\ref{sec:file_open_close}) che prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non toglie che in alcune implementazioni questa tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si è comunque soggetti alla possibilità di una \itindex{race~condition} @@ -3082,7 +3091,7 @@ cancella con \func{unlink}. \end{figure} Uno dei limiti di questa tecnica è che, come abbiamo già accennato in -sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non +sez.~\ref{sec:file_open_close}, questo comportamento di \func{open} può non funzionare (la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare una tecnica alternativa che prevede l'uso della @@ -3252,7 +3261,12 @@ più avanti, quando realizzeremo una nuova versione del monitor visto in sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete. \itindend{memory~mapping} -% TODO fare esempio di mmap anonima +% TODO: fare esempio di mmap anonima + +% TODO: con il kernel 3.2 è stata introdotta un nuovo meccanismo di +% intercomunicazione veloce chiamato Cross Memory Attach, da capire se e come +% trattarlo qui, vedi http://lwn.net/Articles/405346/ +% https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=fcf634098c00dd9cd247447368495f0b79be12d1 \section{L'intercomunicazione fra processi di POSIX} \label{sec:ipc_posix} @@ -3411,7 +3425,7 @@ diversi. La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria; i valori possibili per i vari bit sono quelli visti in -tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i +sez.~\ref{sec:file_open_close} dei quali però \func{mq\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il @@ -3658,7 +3672,7 @@ Se la dimensione specificata da \param{msg\_len} non è sufficiente a contenere il messaggio, entrambe le funzioni, al contrario di quanto avveniva nelle code di messaggi di SysV, ritornano un errore di \errcode{EMSGSIZE} senza estrarre il messaggio. È pertanto opportuno eseguire sempre una chiamata a -\func{mq\_getaddr} prima di eseguire una ricezione, in modo da ottenere la +\func{mq\_getattr} prima di eseguire una ricezione, in modo da ottenere la dimensione massima dei messaggi sulla coda, per poter essere in grado di allocare dei buffer sufficientemente ampi per la lettura. @@ -3729,7 +3743,7 @@ valori di tab.~\ref{tab:sigevent_sigev_notify}.\footnote{la pagina di manuale \const{SIGEV\_SIGNAL}).} Il metodo consigliato è quello di usare \const{SIGEV\_SIGNAL} usando il campo \var{sigev\_signo} per indicare il quale segnale deve essere inviato al processo. Inoltre il campo \var{sigev\_value} è -un puntatore ad una struttura \struct{sigval\_t} (definita in +un puntatore ad una struttura \struct{sigval} (definita in fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale un valore numerico o un indirizzo,\footnote{per il suo uso si riveda la trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali @@ -3841,7 +3855,7 @@ La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e \const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in -tab.~\ref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo +sez.~\ref{sec:file_open_close} dei quali però \func{shm\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di @@ -3863,7 +3877,7 @@ In caso di successo la funzione restituisce un file descriptor associato al segmento di memoria condiviso con le stesse modalità di \func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso - effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene impostato + effetto.} viste in sez.~\ref{sec:file_open_close}; in particolare viene impostato il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando lo stesso nome, restituiranno file descriptor associati allo stesso segmento (così come, nel caso di file di dati, essi sono associati allo stesso @@ -4029,7 +4043,7 @@ automaticamente un nome nella forma \texttt{sem.qualchenome}.\footnote{si ha L'argomento \param{oflag} è quello che controlla le modalità con cui opera la funzione, ed è passato come maschera binaria; i bit corrispondono a quelli utilizzati per l'analogo argomento di \func{open}, anche se dei possibili -valori visti in sez.~\ref{sec:file_open} sono utilizzati soltanto +valori visti in sez.~\ref{sec:file_open_close} sono utilizzati soltanto \const{O\_CREAT} e \const{O\_EXCL}. Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora @@ -4129,7 +4143,7 @@ programma possa proseguire. La seconda variante di \func{sem\_wait} è una estensione specifica che può essere utilizzata soltanto se viene definita la macro \macro{\_XOPEN\_SOURCE} ad un valore di 600 prima di includere \headfile{semaphore.h}, la funzione è -\func{sem\_timedwait}, ed il suo prototipo è: +\funcd{sem\_timedwait}, ed il suo prototipo è: \begin{functions} \headdecl{semaphore.h} @@ -4275,7 +4289,7 @@ prende un valore identico a quello usato per creare il semaforo stesso con il semaforo viene effettivamente cancellato dal sistema soltanto quando tutti i processi che lo avevano aperto lo chiudono. Si segue cioè la stessa semantica usata con \func{unlink} per i file, trattata in dettaglio in -sez.~\ref{sec:file_link}. +sez.~\ref{sec:link_symlink_rename}. Una delle caratteristiche peculiari dei semafori POSIX è che questi possono anche essere utilizzati anche in forma anonima, senza necessità di fare @@ -4607,7 +4621,7 @@ testo alla terminazione di quest'ultimo. % LocalWords: dtime lpid cpid nattac shmall shmmax SHMLBA SHMSEG EOVERFLOW brk % LocalWords: memory shmat shmdt void shmaddr shmflg SVID RND RDONLY rounded % LocalWords: SIGSEGV nattch exit SharedMem ShmCreate memset fill ShmFind home -% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr DirScan ipcs NFS +% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr ipcs NFS % LocalWords: ComputeValues ReadMonitor touch SIGTERM dirmonitor unlink fcntl % LocalWords: LockFile UnlockFile CreateMutex FindMutex LockMutex SETLKW GETLK % LocalWords: UnlockMutex RemoveMutex ReadMutex UNLCK WRLCK RDLCK mapping MAP