X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=prochand.tex;h=3810e41304717abde3a19c34b0484a334ad06ae7;hb=06a2f2c7718cebc7cc4ccb894999028a62b6256d;hp=9717529258164076059db6ad2e9fc6accc8140a7;hpb=e7010c3fbd41a2de44c7b513c5de6e2c6d7ab4b4;p=gapil.git diff --git a/prochand.tex b/prochand.tex index 9717529..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 @@ -1186,15 +1202,15 @@ nuovo riceverne lo stato. \textbf{Macro} & \textbf{Descrizione}\\ \hline \hline - \const{WEXITED} & Ritorna quando un processo figlio è terminato. \\ + \const{WEXITED} & Ritorna quando un processo figlio è terminato.\\ \const{WNOHANG} & Ritorna immediatamente anche se non c'è niente da - notificare. \\ - \const{WSTOPPED} & Ritorna quando un processo figlio è stato fermato. \\ - \const{WCONTINUED}& ritorna quando un processo figlio che era stato - fermato ha ripreso l'esecuzione. \\ + notificare.\\ + \const{WSTOPPED} & Ritorna quando un processo figlio è stato fermato.\\ + \const{WCONTINUED}& Ritorna quando un processo figlio che era stato + fermato ha ripreso l'esecuzione.\\ \const{WNOWAIT} & Lascia il processo ancora in attesa di ricezione, così che una successiva chiamata possa di nuovo riceverne - lo stato. \\ + lo stato.\\ \hline \end{tabular} \caption{Costanti che identificano i bit dell'argomento \param{options} @@ -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 @@ -1516,16 +1533,18 @@ Come accennato in sez.~\ref{sec:intro_multiuser} il modello base\footnote{in realtà già esistono estensioni di questo modello base, che lo rendono più flessibile e controllabile, come le \itindex{capabilities} \textit{capabilities} illustrate in sez.~\ref{sec:proc_capabilities}, le ACL - per i file o il \itindex{Mandatory~Access~Control~(MAC)} \textit{Mandatory - Access Control} di SELinux; inoltre basandosi sul lavoro effettuato con + per i file (vedi sez.~\ref{sec:file_ACL}) o il + \itindex{Mandatory~Access~Control~(MAC)} \textit{Mandatory Access Control} + di \index{SELinux} SELinux; inoltre basandosi sul lavoro effettuato con SELinux, a partire dal kernel 2.5.x, è iniziato lo sviluppo di una - infrastruttura di sicurezza, il \textit{Linux Security Modules}, o LSM, in - grado di fornire diversi agganci a livello del kernel per modularizzare - tutti i possibili controlli di accesso.} di sicurezza di un sistema -unix-like è fondato sui concetti di utente e gruppo, e sulla separazione fra -l'amministratore (\textsl{root}, detto spesso anche \textit{superuser}) che -non è sottoposto a restrizioni, ed il resto degli utenti, per i quali invece -vengono effettuati i vari controlli di accesso. + infrastruttura di sicurezza, i \itindex{Linux~Security~Modules} + \textit{Linux Security Modules}, o LSM, in grado di fornire diversi agganci + a livello del kernel per modularizzare tutti i possibili controlli di + accesso.} di sicurezza di un sistema unix-like è fondato sui concetti di +utente e gruppo, e sulla separazione fra l'amministratore (\textsl{root}, +detto spesso anche \textit{superuser}) che non è sottoposto a restrizioni, ed +il resto degli utenti, per i quali invece vengono effettuati i vari controlli +di accesso. Abbiamo già accennato come il sistema associ ad ogni utente e gruppo due identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per @@ -1562,27 +1581,27 @@ tab.~\ref{tab:proc_uid_gid}. \hline \hline \acr{uid} & \textit{real} & \textsl{user-ID reale} - & indica l'utente che ha lanciato il programma\\ + & Indica l'utente che ha lanciato il programma.\\ \acr{gid} & '' &\textsl{group-ID reale} - & indica il gruppo principale dell'utente che ha lanciato - il programma \\ + & Indica il gruppo principale dell'utente che ha lanciato + il programma.\\ \hline \acr{euid} & \textit{effective} &\textsl{user-ID effettivo} - & indica l'utente usato nel controllo di accesso \\ + & Indica l'utente usato nel controllo di accesso.\\ \acr{egid} & '' & \textsl{group-ID effettivo} - & indica il gruppo usato nel controllo di accesso \\ + & Indica il gruppo usato nel controllo di accesso.\\ -- & -- & \textsl{group-ID supplementari} - & indicano gli ulteriori gruppi cui l'utente appartiene \\ + & Indicano gli ulteriori gruppi cui l'utente appartiene.\\ \hline -- & \textit{saved} & \textsl{user-ID salvato} - & è una copia dell'\acr{euid} iniziale\\ + & È una copia dell'\acr{euid} iniziale.\\ -- & '' & \textsl{group-ID salvato} - & è una copia dell'\acr{egid} iniziale \\ + & È una copia dell'\acr{egid} iniziale.\\ \hline \acr{fsuid} & \textit{filesystem} &\textsl{user-ID di filesystem} - & indica l'utente effettivo per l'accesso al filesystem \\ + & Indica l'utente effettivo per l'accesso al filesystem. \\ \acr{fsgid} & '' & \textsl{group-ID di filesystem} - & indica il gruppo effettivo per l'accesso al filesystem \\ + & Indica il gruppo effettivo per l'accesso al filesystem.\\ \hline \end{tabular} \caption{Identificatori di utente e gruppo associati a ciascun processo con @@ -2109,12 +2128,15 @@ eseguibili,\footnote{una descrizione sommaria di questa funzionalit ma non essendo implementata non ne tratteremo qui.} in modo da poter stabilire quali capacità possono essere utilizzate quando viene messo in esecuzione uno specifico programma; attualmente però questa funzionalità non è -implementata.\footnote{per attualmente si intende fino al kernel 2.6.13, e - finora non è disponibile al momento neanche presente nessuna realizzazione - sperimentale delle specifiche POSIX.1e, anche se esistono dei patch di - sicurezza del kernel, come LIDS (vedi - \href{http://www.lids.org}{\texttt{http://www.lids.org/})} che realizzano - qualcosa di simile.} +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}{\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] @@ -2195,7 +2217,8 @@ implementata.\footnote{per attualmente si intende fino al kernel 2.6.13, e (limitatamente a quelle che il processo chiamante ha nel suo insieme di capacità permesse) da qualunque processo.\\ - \const{CAP\_LINUX\_IMMUTABLE}& la capacità di impostare gli attributi +% 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 filesystem che supporta questi @@ -2206,7 +2229,7 @@ implementata.\footnote{per attualmente si intende fino al kernel 2.6.13, e \const{CAP\_NET\_BROADCAST}& La capacità di consentire l'uso di socket in \itindex{broadcast} \textit{broadcast} e \itindex{multicast} \textit{multicast}.\\ - \const{CAP\_NET\_ADMIN} & la capacità di eseguire alcune operazioni + \const{CAP\_NET\_ADMIN} & La capacità di eseguire alcune operazioni privilegiate sulla rete (impostare le opzioni privilegiate dei socket, abilitare il \itindex{multicast} \textit{multicasting}, @@ -2247,12 +2270,12 @@ implementata.\footnote{per attualmente si intende fino al kernel 2.6.13, e sistema.\\ \const{CAP\_SYS\_NICE} & La capacità di modificare le priorità dei processi (vedi sez.~\ref{sec:proc_priority}). \\ - \const{CAP\_SYS\_RESOURCE}& la capacità di superare le limitazioni sulle + \const{CAP\_SYS\_RESOURCE}& La capacità di superare le limitazioni sulle risorse, aumentare le quote disco, usare lo spazio disco riservato all'amministratore.\\ \const{CAP\_SYS\_TIME} & La capacità di modificare il tempo di sistema (vedi sez.~\ref{sec:sys_time}).\\ - \const{CAP\_SYS\_TTY\_CONFIG}& la capacità di simulare un \textit{hangup} + \const{CAP\_SYS\_TTY\_CONFIG}& La capacità di simulare un \textit{hangup} della console, con la funzione \func{vhangup}.\\ \const{CAP\_MKNOD} & La capacità di creare file di dispositivo con la @@ -2767,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} @@ -2855,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 @@ -3093,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 @@ -3101,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 @@ -3149,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 @@ -3156,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 @@ -3295,7 +3326,6 @@ dato che in Linux questo intervallo di tempo questa funzione ritorna sempre un valore di 150 millisecondi, e non importa specificare il PID di un processo reale. - Come accennato ogni processo che usa lo scheduling real-time può rilasciare volontariamente la CPU; questo viene fatto attraverso la funzione \funcd{sched\_yield}, il cui prototipo è: @@ -3315,8 +3345,12 @@ l'esecuzione non sar in modalità \textit{fifo}, per permettere l'esecuzione degli altri processi con pari priorità quando la sezione più urgente è finita. +% TODO: con il 2.6.23 il comportamento è stato leggermente modificato ed è +% stato introdotto /proc/sys/kernel/sched_compat_yield da mettere a 1 per aver +% la compatibilità con il precedente. -\subsection{Il controllo dello \textit{scheduler} per i sistemi multiprocessore} +\subsection{Il controllo dello \textit{scheduler} per i sistemi + multiprocessore} \label{sec:proc_sched_multiprocess} Infine con il supporto dei sistemi multiprocessore sono state introdotte delle @@ -3545,7 +3579,7 @@ qualunque momento, e le operazioni di un eventuale \textit{signal handler} sono compiute nello stesso spazio di indirizzi del processo. Per questo, anche il solo accesso o l'assegnazione di una variabile possono non essere più operazioni atomiche (torneremo su questi aspetti in -sez.~\ref{sec:sig_control}). +sez.~\ref{sec:sig_adv_control}). In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t}, il cui accesso è assicurato essere atomico. In pratica comunque si può