From 7ab2f18da45ad6da904be851e3a864adeac8cb10 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 26 Oct 2002 13:23:47 +0000 Subject: [PATCH] Correzioni ortografiche e aggiornamento di alcune voci per l'indice --- fileadv.tex | 23 ++++++++------ intro.tex | 14 ++++----- ipc.tex | 22 ++++++------- prochand.tex | 87 +++++++++++++++++++++++++++------------------------- signal.tex | 27 ++++++++-------- 5 files changed, 90 insertions(+), 83 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index 1932eca..3d1c9f8 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -33,7 +33,8 @@ affrontare nelle operazioni di I/O, che devono eseguire operazioni che possono bloccarsi su più file descriptor: mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata -inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un deadlock. +inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un +\textit{deadlock}. Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire questo tipo di comportamento aprendo un file in modalità @@ -976,7 +977,8 @@ come maschera binaria ottenuta dall'OR di uno o pi riportati sul file. Ne viene fatta una copia privata cui solo il processo chiamante ha accesso. Le modifiche sono mantenute attraverso - il meccanismo del \textit{copy on write} e + il meccanismo del + \textit{copy on write}\index{copy on write} e salvate su swap in caso di necessità. Non è specificato se i cambiamenti sul file originale vengano riportati sulla regione @@ -988,7 +990,8 @@ come maschera binaria ottenuta dall'OR di uno o pi \macro{MAP\_EXECUTABLE}& Ignorato. \\ \macro{MAP\_NORESERVE} & Si usa con \macro{MAP\_PRIVATE}. Non riserva delle pagine di swap ad uso del meccanismo di - \textit{copy on write} per mantenere le + \textit{copy on write}\index{copy on write} + per mantenere le modifiche fatte alla regione mappata, in questo caso dopo una scrittura, se non c'è più memoria disponibile, si ha l'emissione di @@ -1234,8 +1237,8 @@ sovrapposizioni, e garantire la atomicit La prima modalità di file locking che è stata implementata nei sistemi unix-like è quella che viene usualmente chiamata \textit{advisory - locking},\footnote{Stevens in APUE fa riferimento a questo argomento come al - \textit{record locking}, dizione utilizzata anche dal manuale delle + locking},\footnote{Stevens in \cite{APUE} fa riferimento a questo argomento + come al \textit{record locking}, dizione utilizzata anche dal manuale delle \acr{glibc}; nelle pagine di manuale si parla di \textit{discretionary file lock} per \func{fcntl} e di \textit{advisory locking} per \func{flock}, mentre questo nome viene usato anche da Stevens per riferirsi al @@ -1272,7 +1275,7 @@ sono implementati in maniera completamente indipendente nelle due interfacce, che pertanto possono coesistere senza interferenze. Entrambe le interfacce prevedono la stessa procedura di funzionamento: si -inizia sempre con il richiere l'opportuno \textit{file lock} (un +inizia sempre con il richiedere l'opportuno \textit{file lock} (un \textit{exclusive lock} per una scrittura, uno \textit{shared lock} per una lettura) prima di eseguire l'accesso ad un file. Se il lock viene acquisito il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un @@ -1329,14 +1332,14 @@ costanti riportate in \tabref{tab:file_flock_operation}. I primi due valori, \macro{LOCK\_SH} e \macro{LOCK\_EX} permettono di richiedere un \textit{file lock}, ed ovviamente devono essere usati in maniera alternativa. Se si specifica anche \macro{LOCK\_NB} la funzione non si -bloccherà qualora il lock non possa essere aqcuisito, ma ritornerà subito con +bloccherà qualora il lock non possa essere acquisito, ma ritornerà subito con un errore di \macro{EWOULDBLOCK}. Per rilasciare un lock si dovrà invece usare \macro{LOCK\_NB}. La semantica del file locking di BSD è diversa da quella del file locking POSIX, in particolare per quanto riguarda il comportamento dei lock nei confronti delle due funzioni \func{dup} e \func{fork}. Per capire queste -differenze occore prima descrivere con maggiore dettaglio come viene +differenze occorre prima descrivere con maggiore dettaglio come viene realizzato il file locking nel kernel. In \figref{fig:file_flock_struct} si è riportato uno schema essenziale @@ -1473,7 +1476,7 @@ struct flock { L'operazione effettivamente svolta dalla funzione è stabilita dal valore dall'argomento \param{cmd} che, come già riportato in \secref{sec:file_fcntl}, -specifica l'azione da compiere; i valori relativi al file loking sono tre: +specifica l'azione da compiere; i valori relativi al file locking sono tre: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\macro{F\_GETLK}] verifica se il file lock specificato dalla struttura puntata da \param{lock} non è bloccato da qualche altro lock: in caso @@ -1574,7 +1577,7 @@ allo stesso file (che sia stato ottenuto con una \func{dup} o con una che quello che conta è solo il \acr{pid} del processo. Da questo deriva una ulteriore sottile differenza di comportamento: dato che alla chiusura di un file i lock ad esso associati vengono rimossi, nella semantica POSIX basterà -chiudere un file descriptor per cancellare tutti i lock realtivi al file cui +chiudere un file descriptor per cancellare tutti i lock relativi al file cui esso faceva riferimento, anche se questi fossero stati creati usando altri file descriptor che restano aperti. diff --git a/intro.tex b/intro.tex index 06bc957..9c682f7 100644 --- a/intro.tex +++ b/intro.tex @@ -52,13 +52,13 @@ all'hardware, mentre i programmi normali vengono eseguiti in modalit (e non possono accedere direttamente alle zone di memoria riservate o alle porte di input/output). -Una parte del kernel, lo \textit{scheduler}, si occupa di stabilire, ad -intervalli fissi e sulla base di un opportuno calcolo delle priorità, quale -``processo'' deve essere posto in esecuzione (il cosiddetto \textit{preemptive - scheduling}\index{preemptive scheduling}). Questo verrà comunque eseguito in -modalità protetta; quando necessario il processo potrà accedere alle risorse -hardware soltanto attraverso delle opportune chiamate al sistema che -restituiranno il controllo al kernel. +Una parte del kernel, lo \textit{scheduler}\index{scheduler}, si occupa di +stabilire, ad intervalli fissi e sulla base di un opportuno calcolo delle +priorità, quale ``processo'' deve essere posto in esecuzione (il cosiddetto +\textit{preemptive scheduling}\index{preemptive scheduling}). Questo verrà +comunque eseguito in modalità protetta; quando necessario il processo potrà +accedere alle risorse hardware soltanto attraverso delle opportune chiamate al +sistema che restituiranno il controllo al kernel. La memoria viene sempre gestita dal kernel attraverso il meccanismo della \textsl{memoria virtuale}\index{memoria virtuale}, che consente di assegnare a diff --git a/ipc.tex b/ipc.tex index da8d85a..f06dfbf 100644 --- a/ipc.tex +++ b/ipc.tex @@ -830,7 +830,7 @@ 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 -emtrambe le direzioni. Il prototipo della funzione è: +entrambe le direzioni. Il prototipo della funzione è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/socket.h} @@ -903,7 +903,7 @@ file, un contatore del numero di riferimenti che ne indichi l'essere in uso, essi possono essere cancellati anche se ci sono dei processi che li stanno utilizzando, con tutte le conseguenze (negative) del caso. -Un'ulteriore caratterestica negativa è che gli oggetti usati nel System V IPC +Un'ulteriore caratteristica negativa è che gli oggetti usati nel System V IPC vengono creati direttamente dal kernel, e sono accessibili solo specificando il relativo \textsl{identificatore}. Questo è un numero progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a ciascuno di essi @@ -1716,13 +1716,13 @@ void HandSIGTERM(int signo) { \end{figure} In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti -primcipali del codice del nuovo server (il codice completo è nel file +principali del codice del nuovo server (il codice completo è nel file \file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi per permettere una comunicazione indipendente fra il server ed i vari client, usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile in quanto, al contrario di una fifo, la lettura di una coda di messaggi può -non essere sequanziale, proprio grazie alla classificazione dei messaggi sulla +non essere sequenziale, proprio grazie alla classificazione dei messaggi sulla base del loro tipo. Il programma, oltre alle solite variabili per il nome del file da cui leggere @@ -1752,7 +1752,7 @@ Finita la fase di inizializzazione il server esegue in permanenza il ciclo principale (\texttt{\small 32--41}). Questo inizia (\texttt{\small 33}) con il porsi in attesa di un messaggio di richiesta da parte di un client; si noti infatti come \func{msgrcv} richieda un messaggio con \var{mtype} uguale a 1: -questo è il valore usato per le richieste dato che corriponde al \acr{pid} di +questo è il valore usato per le richieste dato che corrisponde al \acr{pid} di \cmd{init}, che non può essere un client. L'uso del flag \macro{MSG\_NOERROR} è solo per sicurezza, dato che i messaggi di richiesta sono di dimensione fissa (e contengono solo il \acr{pid} del client). @@ -1820,7 +1820,7 @@ non viene chiamata con il flag di creazione in quanto la coda deve essere preesistente. In caso di errore (ad esempio se il server non è stato avviato) il programma termina immediatamente. -Una volta acquistito l'identificatore della coda il client compone il +Una volta acquisito l'identificatore della coda il client compone il messaggio di richiesta (\texttt{\small 12--13}) in \var{msg\_read}, usando 1 per il tipo ed inserendo il proprio \acr{pid} come dato da passare al server. Calcolata (\texttt{\small 14}) la dimensione, provvede (\texttt{\small 15}) ad @@ -1832,7 +1832,7 @@ tipo corrispondente al valore del \acr{pid} inviato nella richiesta. L'ultimo passo (\texttt{\small 17}) prima di uscire è quello di stampare a video il messaggio ricevuto. -Benché funzionante questa archietettura risente dello stesso inconveniente +Benché funzionante questa architettura risente dello stesso inconveniente visto anche nel caso del precedente server basato sulle fifo; se il client viene interrotto dopo l'invio del messaggio di richiesta e prima della lettura della risposta, quest'ultima resta nella coda (così come per le fifo si aveva @@ -2001,7 +2001,7 @@ struct sem { \label{fig:ipc_sem} \end{figure} -I dati mentenuti nella struttura, ed elencati in \figref{fig:ipc_sem}, +I dati mantenuti nella struttura, ed elencati in \figref{fig:ipc_sem}, indicano rispettivamente: \begin{description*} \item[\var{semval}] il valore numerico del semaforo. @@ -2364,14 +2364,14 @@ Alla creazione di un nuovo insieme viene allocata una nuova strutture \var{semid\_ds} ed il relativo vettore di strutture \var{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 creaa una struttura \var{sem\_queue} che viene aggiunta in fondo alla +kernel crea una struttura \var{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 \var{semid\_ds}.}. Nella struttura viene memorizzato il riferimento alle operazioni richieste (nel campo \var{sops}, che è un puntatore ad una struttura \var{sembuf}) e al processo corrente (nel campo \var{sleeper}) poi -quest'ultimo viene messo stato di attesa e viene invocato lo scheduler per -passare all'esecuzione di un altro processo. +quest'ultimo viene messo stato di attesa e viene invocato lo +scheduler\index{scheduler} per passare all'esecuzione di un altro processo. Se invece tutte le operazioni possono avere successo queste vengono eseguite immediatamente, dopo di che il kernel esegue una scansione della coda di diff --git a/prochand.tex b/prochand.tex index 48af070..4bb15c6 100644 --- a/prochand.tex +++ b/prochand.tex @@ -132,21 +132,22 @@ riprese), \end{figure} -Come accennato in \secref{sec:intro_unix_struct} è lo \textit{scheduler} che -decide quale processo mettere in esecuzione; esso viene eseguito ad ogni -system call ed ad ogni interrupt,\footnote{più in una serie di altre - occasioni. NDT completare questa parte.} (ma può essere anche attivato -esplicitamente). Il timer di sistema provvede comunque a che esso sia invocato -periodicamente, generando un interrupt periodico secondo la frequenza -specificata dalla costante \macro{HZ}, definita in \file{asm/param.h}, ed il -cui valore è espresso in Hertz.\footnote{Il valore usuale di questa costante è - 100, per tutte le architetture eccetto l'alpha, per la quale è 1000. Occorre - fare attenzione a non confondere questo valore con quello dei clock tick - (vedi \secref{sec:sys_unix_time}).} +Come accennato in \secref{sec:intro_unix_struct} è lo +\textit{scheduler}\index{scheduler} che decide quale processo mettere in +esecuzione; esso viene eseguito ad ogni system call ed ad ogni +interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa + parte.} (ma può essere anche attivato esplicitamente). Il timer di sistema +provvede comunque a che esso sia invocato periodicamente, generando un +interrupt periodico secondo la frequenza specificata dalla costante +\macro{HZ}, definita in \file{asm/param.h}, ed il cui valore è espresso in +Hertz.\footnote{Il valore usuale di questa costante è 100, per tutte le + architetture eccetto l'alpha, per la quale è 1000. Occorre fare attenzione a + non confondere questo valore con quello dei clock tick (vedi + \secref{sec:sys_unix_time}).} %Si ha cioè un interrupt dal timer ogni centesimo di secondo. -Ogni volta che viene eseguito, lo \textit{scheduler} effettua il calcolo delle -priorità dei vari processi attivi (torneremo su questo in +Ogni volta che viene eseguito, lo \textit{scheduler}\index{scheduler} effettua +il calcolo delle priorità dei vari processi attivi (torneremo su questo in \secref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in esecuzione fino alla successiva invocazione. @@ -459,15 +460,15 @@ Go to next child Esaminiamo questo risultato: una prima conclusione che si può trarre è che non si può dire quale processo fra il padre ed il figlio venga eseguito per primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo - scheduler di Ingo Molnar che esegue sempre per primo il figlio; per - mantenere la portabilità è opportuno non fare comunque affidamento su questo - comportamento.} dopo la chiamata a \func{fork}; dall'esempio si può notare -infatti come nei primi due cicli sia stato eseguito per primo il padre (con la -stampa del \acr{pid} del nuovo processo) per poi passare all'esecuzione del -figlio (completata con i due avvisi di esecuzione ed uscita), e tornare -all'esecuzione del padre (con la stampa del passaggio al ciclo successivo), -mentre la terza volta è stato prima eseguito il figlio (fino alla conclusione) -e poi il padre. + scheduler\index{scheduler} di Ingo Molnar che esegue sempre per primo il + figlio; per mantenere la portabilità è opportuno non fare comunque + affidamento su questo comportamento.} dopo la chiamata a \func{fork}; +dall'esempio si può notare infatti come nei primi due cicli sia stato eseguito +per primo il padre (con la stampa del \acr{pid} del nuovo processo) per poi +passare all'esecuzione del figlio (completata con i due avvisi di esecuzione +ed uscita), e tornare all'esecuzione del padre (con la stampa del passaggio al +ciclo successivo), mentre la terza volta è stato prima eseguito il figlio +(fino alla conclusione) e poi il padre. In generale l'ordine di esecuzione dipenderà, oltre che dall'algoritmo di scheduling usato dal kernel, dalla particolare situazione in si trova la @@ -1837,9 +1838,10 @@ quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag \label{sec:proc_priority} In questa sezione tratteremo più approfonditamente i meccanismi con il quale -lo \textit{scheduler} assegna la CPU ai vari processi attivi. In particolare -prenderemo in esame i vari meccanismi con cui viene gestita l'assegnazione del -tempo di CPU, ed illustreremo le varie funzioni di gestione. +lo \textit{scheduler}\index{scheduler} assegna la CPU ai vari processi attivi. +In particolare prenderemo in esame i vari meccanismi con cui viene gestita +l'assegnazione del tempo di CPU, ed illustreremo le varie funzioni di +gestione. \subsection{I meccanismi di \textit{scheduling}} @@ -1857,8 +1859,8 @@ contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative multitasking}) non sono i singoli processi, ma il kernel stesso a decidere quando la CPU deve essere passata ad un altro processo. Come accennato in \secref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione -apposita del kernel, lo \textit{scheduler}, il cui scopo è quello di -distribuire al meglio il tempo di CPU fra i vari processi. +apposita del kernel, lo \textit{scheduler}\index{scheduler}, il cui scopo è +quello di distribuire al meglio il tempo di CPU fra i vari processi. La cosa è resa ancora più complicata dal fatto che con le architetture multi-processore si deve anche scegliere quale sia la CPU più opportuna da @@ -1986,16 +1988,17 @@ viene assegnato ad un altro campo della struttura (\var{counter}) quando il processo viene eseguito per la prima volta e diminuito progressivamente ad ogni interruzione del timer. -Quando lo 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 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 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 verranno messi in esecuzione. +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 + 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 +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 +verranno messi in esecuzione. La priorità di un processo è così controllata attraverso il valore di \var{nice}, che stabilisce la durata della \textit{time-slice}; per il @@ -2138,11 +2141,11 @@ quando si lavora con processi che usano priorit 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 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 -tocca al kernel decidere quale deve essere eseguito. +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 +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: diff --git a/signal.tex b/signal.tex index 48d45b3..7cbda4f 100644 --- a/signal.tex +++ b/signal.tex @@ -140,9 +140,9 @@ Si dice che il segnale viene \textsl{consegnato} al processo (dall'inglese \textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre per tutto il tempo che passa fra la generazione del segnale e la sua consegna esso è detto \textsl{pendente} (o \textit{pending}). In genere questa -procedura viene effettuata dallo scheduler quando, riprendendo l'esecuzione -del processo in questione, verifica la presenza del segnale nella -\var{task\_struct} e mette in esecuzione il gestore. +procedura viene effettuata dallo scheduler\index{scheduler} quando, +riprendendo l'esecuzione del processo in questione, verifica la presenza del +segnale nella \var{task\_struct} e mette in esecuzione il gestore. In questa semantica un processo ha la possibilità di bloccare la consegna dei segnali, in questo caso, se l'azione per il suddetto segnale non è quella di @@ -211,11 +211,12 @@ verr ignorarlo). Normalmente l'invio al processo che deve ricevere il segnale è immediato ed -avviene non appena questo viene rimesso in esecuzione dallo scheduler che -esegue l'azione specificata. Questo a meno che il segnale in questione non sia -stato bloccato prima della notifica, nel qual caso l'invio non avviene ed il -segnale resta \textsl{pendente} indefinitamente. Quando lo si sblocca il -segnale \textsl{pendente} sarà subito notificato. +avviene non appena questo viene rimesso in esecuzione dallo +scheduler\index{scheduler} che esegue l'azione specificata. Questo a meno che +il segnale in questione non sia stato bloccato prima della notifica, nel qual +caso l'invio non avviene ed il segnale resta \textsl{pendente} +indefinitamente. Quando lo si sblocca il segnale \textsl{pendente} sarà subito +notificato. Si ricordi però che se l'azione specificata per un segnale è quella di essere ignorato questo sarà scartato immediatamente al momento della sua generazione, @@ -1347,11 +1348,11 @@ Chiaramente, anche se il tempo pu nanosecondo, la precisione di \func{nanosleep} è determinata dalla risoluzione temporale del timer di sistema. Perciò la funzione attenderà comunque il tempo specificato, ma prima che il processo possa tornare ad essere eseguito -occorrerà almeno attendere il successivo giro di scheduler e cioè un tempo che -a seconda dei casi può arrivare fino a 1/\macro{HZ}, (sempre che il sistema -sia scarico ed il processa venga immediatamente rimesso in esecuzione); per -questo motivo il valore restituito in \param{rem} è sempre arrotondato al -multiplo successivo di 1/\macro{HZ}. +occorrerà almeno attendere il successivo giro di scheduler\index{scheduler} e +cioè un tempo che a seconda dei casi può arrivare fino a 1/\macro{HZ}, (sempre +che il sistema sia scarico ed il processa venga immediatamente rimesso in +esecuzione); per questo motivo il valore restituito in \param{rem} è sempre +arrotondato al multiplo successivo di 1/\macro{HZ}. In realtà è possibile ottenere anche pause più precise del centesimo di secondo usando politiche di scheduling real time come \macro{SCHED\_FIFO} o -- 2.30.2