X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=prochand.tex;h=3810e41304717abde3a19c34b0484a334ad06ae7;hb=06a2f2c7718cebc7cc4ccb894999028a62b6256d;hp=7301bae11403ff1815edfe13b2c8085766f2aa72;hpb=02950a8e6544100a795b38e88f30d1f97ad67494;p=gapil.git diff --git a/prochand.tex b/prochand.tex index 7301bae..3810e41 100644 --- a/prochand.tex +++ b/prochand.tex @@ -155,7 +155,8 @@ periodico secondo la frequenza specificata dalla costante \const{HZ},\footnote{fino al kernel 2.4 il valore usuale di questa costante era 100, per tutte le architetture eccetto l'alpha, per la quale era 1000, nel 2.6 è stato portato a 1000 su tutte le architetture; occorre fare - attenzione a non confondere questo valore con quello dei clock tick (vedi + attenzione a non confondere questo valore con quello dei + \itindex{clock~tick} \textit{clock tick} (vedi sez.~\ref{sec:sys_unix_time}).} definita in \file{asm/param.h}, ed il cui valore è espresso in Hertz.\footnote{a partire dal kernel 2.6.21 è stato introdotto (a cura di Ingo Molnar) un meccanismo completamente diverso, @@ -193,9 +194,9 @@ abbastanza limitata sulle cause della terminazione del processo figlio. Quando un processo ha concluso il suo compito o ha incontrato un errore non risolvibile esso può essere terminato con la funzione \func{exit} (si veda quanto discusso in sez.~\ref{sec:proc_conclusion}). La vita del processo però -termina solo quando la notifica della sua conclusione viene ricevuta dal -processo padre, a quel punto tutte le risorse allocate nel sistema ad esso -associate vengono rilasciate. +termina completamente solo quando la notifica della sua conclusione viene +ricevuta dal processo padre, a quel punto tutte le risorse allocate nel +sistema ad esso associate vengono rilasciate. Avere due processi che eseguono esattamente lo stesso codice non è molto utile, normalmente si genera un secondo processo per affidargli l'esecuzione @@ -217,7 +218,6 @@ prima ritorna due volte (nel processo padre e nel figlio) mentre la seconda non ritorna mai (in quanto con essa viene eseguito un altro programma). - \section{Le funzioni di base}% della gestione dei processi} \label{sec:proc_handling} @@ -249,10 +249,12 @@ basso disponibile a partire da un minimo di 300,\footnote{questi valori, fino al kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in \file{threads.h} e direttamente in \file{fork.c}, con il kernel 2.5.x e la nuova interfaccia per i thread creata da Ingo Molnar anche il meccanismo di - allocazione dei \acr{pid} è stato modificato.} che serve a riservare i -\acr{pid} più bassi ai processi eseguiti direttamente dal kernel. Per questo -motivo, come visto in sez.~\ref{sec:proc_hierarchy}, il processo di avvio -(\cmd{init}) ha sempre il \acr{pid} uguale a uno. + allocazione dei \acr{pid} è stato modificato; il valore massimo è + impostabile attraverso il file \procfile{/proc/sys/kernel/pid\_max} e di + default vale 32768.} che serve a riservare i \acr{pid} più bassi ai processi +eseguiti direttamente dal kernel. Per questo motivo, come visto in +sez.~\ref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha sempre il +\acr{pid} uguale a uno. Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui sono stati creati, questo viene chiamato in genere \acr{ppid} (da @@ -430,7 +432,6 @@ Se eseguiamo il comando\footnote{che senza specificare attese (come si può notare in (\texttt{\small 17--19}) i valori predefiniti specificano di non attendere), otterremo come output sul terminale: - \footnotesize \begin{verbatim} [piccardi@selidor sources]$ export LD_LIBRARY_PATH=./; ./forktest 3 @@ -451,17 +452,14 @@ Go to next child \normalsize 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 - \itindex{scheduler} \textit{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. +si può dire quale processo fra il padre ed il figlio venga eseguito per primo +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 \itindex{scheduler} scheduling usato dal kernel, dalla particolare situazione @@ -478,6 +476,24 @@ occorrer rischio di incorrere nelle cosiddette \itindex{race~condition} \textit{race condition} (vedi sez.~\ref{sec:proc_race_cond}). +In realtà a partire dal kernel 2.5.2-pre10 il nuovo \itindex{scheduler} +\textit{scheduler} di Ingo Molnar esegue sempre per primo il +figlio;\footnote{i risultati precedenti sono stati ottenuti usando un kernel + della serie 2.4.} questa è una ottimizzazione che serve a evitare che il +padre, effettuando per primo una operazione di scrittura in memoria, attivi il +meccanismo del \itindex{copy~on~write} \textit{copy on write}. Questa +operazione infatti potrebbe risultare del tutto inutile qualora il figlio +fosse stato creato solo per eseguire una \func{exec}, in tal caso infatti si +invocherebbe un'altro proramma scartando completamente lo spazio degli +indirizzi, rendendo superflua la copia della memoria modificata dal padre. + +Eseguendo sempre per primo il figlio la \func{exec} verrebbe effettuata subito +avendo così la certezza che il \itindex{copy~on~write} \textit{copy on write} +viene utilizzato solo quando necessario. Quanto detto in precedenza vale +allora soltanto per i kernel fino al 2.4; per mantenere la portabilità è però +opportuno non fare affidamento su questo comportamento, che non si riscontra +in altri Unix e nelle versioni del kernel precendenti a quella indicata. + Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli processi completamente separati, le modifiche delle variabili nei processi figli (come l'incremento di \var{i} in \texttt{\small 31}) sono visibili solo @@ -489,7 +505,6 @@ Un secondo aspetto molto importante nella creazione dei processi figli quello dell'interazione dei vari processi con i file; per illustrarlo meglio proviamo a redirigere su un file l'output del nostro programma di test, quello che otterremo è: - \footnotesize \begin{verbatim} [piccardi@selidor sources]$ ./forktest 3 > output @@ -537,7 +552,7 @@ ogni figlio riceve una copia della memoria del padre, esso ricever quanto c'è nel buffer delle funzioni di I/O, comprese le linee scritte dal padre fino allora. Così quando il buffer viene scritto su disco all'uscita del figlio, troveremo nel file anche tutto quello che il processo padre aveva -scritto prima della sua creazione. E alla fine del file (dato che in questo +scritto prima della sua creazione. E alla fine del file (dato che in questo caso il padre esce per ultimo) troveremo anche l'output completo del padre. L'esempio ci mostra un altro aspetto fondamentale dell'interazione con i file, @@ -726,6 +741,8 @@ che sia cos terminato (si potrebbe avere cioè quello che si chiama un processo \textsl{orfano}). +% TODO verificare il reparenting + Questa complicazione viene superata facendo in modo che il processo orfano venga \textsl{adottato} da \cmd{init}. Come già accennato quando un processo termina, il kernel controlla se è il padre di altri processi in esecuzione: in @@ -735,7 +752,6 @@ avr cui riportare il suo stato di terminazione. Come verifica di questo comportamento possiamo eseguire il nostro programma \cmd{forktest} imponendo a ciascun processo figlio due secondi di attesa prima di uscire, il risultato è: - \footnotesize \begin{verbatim} [piccardi@selidor sources]$ ./forktest -c2 3 @@ -1226,7 +1242,8 @@ ritorno di \func{waitid} verranno avvalorati i seguenti campi: \const{CLD\_STOPPED}, \const{CLD\_CONTINUED} (vedi tab.~\ref{xxx_si_code}). \end{basedescript} -%TODO mettere riferimento alla tabella giusta +%TODO mettere riferimento alla tabella giusta (vedere man credentials e man +% waitid) Infine Linux, seguendo un'estensione di BSD, supporta altre due funzioni per la lettura dello stato di terminazione di un processo, analoghe alle @@ -1255,7 +1272,7 @@ utilizzata anche dalla funzione \func{getrusage} (vedi sez.~\ref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un processo; la sua definizione è riportata in fig.~\ref{fig:sys_rusage_struct}. -\subsection{Le funzioni \func{exec}} +\subsection{La funzione \func{exec} e le funzioni di esecuzione dei programmi} \label{sec:proc_exec} Abbiamo già detto che una delle modalità principali con cui si utilizzano i @@ -1488,7 +1505,7 @@ chiamato come se si fosse eseguito il comando \cmd{interpreter [argomenti] lunga restituisce un errore di \const{ENAMETOOLONG}, una comparazione dei vari comportamenti si trova su \href{http://www.in-ulm.de/~mascheck/various/shebang/} - {\texttt{http://www.in-ulm.de/\tild mascheck/various/shebang/}}.} + {\textsf{http://www.in-ulm.de/\tild mascheck/various/shebang/}}.} Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è basata la gestione dei processi in Unix: con \func{fork} si crea un nuovo @@ -2115,9 +2132,12 @@ implementata.\footnote{per attualmente si intende fino al kernel 2.6.23; benché l'infrastruttura per crearla sia presente (vedi anche sez.~\ref{sec:file_xattr}) finora non è disponibile nessuna realizzazione delle specifiche POSIX.1e, esistono però dei patch di sicurezza del kernel, - come LIDS (vedi \href{http://www.lids.org}{\texttt{http://www.lids.org/})} + come LIDS (vedi \href{http://www.lids.org}{\textsf{http://www.lids.org/})} che realizzano qualcosa di simile.} +% TODO verificare per process capability bounding set, vedi: +% http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b7391de67da515c91f48aa371de77cb6cc5c07e + \begin{table}[!h!bt] \centering @@ -2197,6 +2217,7 @@ implementata.\footnote{per attualmente si intende fino al kernel 2.6.23; (limitatamente a quelle che il processo chiamante ha nel suo insieme di capacità permesse) da qualunque processo.\\ +% TODO cambiata nel 2.4.24 rc1 ? \const{CAP\_LINUX\_IMMUTABLE}& La capacità di impostare gli attributi \textit{immutable} e \itindex{append~mode} \textit{append only} per i file su un @@ -2769,6 +2790,8 @@ funzione. % TODO documentare prctl ... +% TODO: rivedere alla luce degli aggiornamenti del 2.6 (man sched_setscheduler) + \section{La gestione della priorità di esecuzione} \label{sec:proc_priority} @@ -2857,6 +2880,8 @@ fintanto che esso si trova in uno qualunque degli altri stati. \label{tab:proc_proc_states} \end{table} +% TODO nel 2.6.25 è stato aggiunto TASK_KILLABLE, da capire dova va messo. + Si deve quindi tenere presente che l'utilizzo della CPU è soltanto una delle risorse che sono necessarie per l'esecuzione di un programma, e a seconda dello scopo del programma non è detto neanche che sia la più importante (molti @@ -3095,7 +3120,7 @@ tocca al kernel decidere quale deve essere eseguito. Il meccanismo con cui vengono gestiti questi processi dipende dalla politica di scheduling che si è scelta; lo standard ne prevede due: \begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}} -\item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito +\item[\textsf{FIFO}] \textit{First In First Out}. Il processo viene eseguito fintanto che non cede volontariamente la CPU (con \func{sched\_yield}), si blocca, finisce o viene interrotto da un processo a priorità più alta. Se il processo viene interrotto da uno a priorità più alta esso resterà in cima @@ -3103,7 +3128,7 @@ scelta; lo standard ne prevede due: più alta diverranno inattivi. Se invece lo si blocca volontariamente sarà posto in coda alla lista (ed altri processi con la stessa priorità potranno essere eseguiti). -\item[\textit{RR}] \textit{Round Robin}. Il comportamento è del tutto analogo +\item[\textsf{RR}] \textit{Round Robin}. Il comportamento è del tutto analogo a quello precedente, con la sola differenza che ciascun processo viene eseguito al massimo per un certo periodo di tempo (la cosiddetta \textit{time slice}) dopo di che viene automaticamente posto in fondo alla @@ -3151,6 +3176,8 @@ assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. \const{SCHED\_RR} & Scheduling real-time con politica \textit{Round Robin}. \\ \const{SCHED\_OTHER}& Scheduling ordinario.\\ + \const{SCHED\_BATCH}& Scheduling ordinario con l'assunzione ulteriore di + lavoro \textit{CPU intensive}.\footnotemark\\ \hline \end{tabular} \caption{Valori dell'argomento \param{policy} per la funzione @@ -3158,6 +3185,8 @@ assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. \label{tab:proc_sched_policy} \end{table} +\footnotetext{introdotto con il kernel 2.6.16.} + Il valore della priorità è passato attraverso la struttura \struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui solo campo attualmente definito è \var{sched\_priority}, che nel caso delle