X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=prochand.tex;h=7e882abcd86f9ebdc60a8a247c572a1ebe8160e0;hp=8120b9f6f55b8794c4ba694f6637922196b5a72c;hb=9a577c89dd563aacbc619e09bf8b6d99b533274a;hpb=60e682c9d632073938de25c85bc9a984528d349a diff --git a/prochand.tex b/prochand.tex index 8120b9f..7e882ab 100644 --- a/prochand.tex +++ b/prochand.tex @@ -136,9 +136,8 @@ struttura delle principali informazioni contenute nella \struct{task\_struct} (che in seguito incontreremo a più riprese), è mostrato in fig.~\ref{fig:proc_task_struct}. -\begin{figure}[htb] - \centering - \includegraphics[width=14cm]{img/task_struct} +\begin{figure}[!htb] + \centering \includegraphics[width=14cm]{img/task_struct} \caption{Schema semplificato dell'architettura delle strutture usate dal kernel nella gestione dei processi.} \label{fig:proc_task_struct} @@ -372,9 +371,9 @@ sempre un solo padre (il cui \acr{pid} può sempre essere ottenuto con \func{getppid}, vedi sez.~\ref{sec:proc_pid}) per cui si usa il valore nullo, che non è il \acr{pid} di nessun processo. -\begin{figure}[!htb] +\begin{figure}[!htbp] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/ForkTest.c} \end{minipage} \normalsize @@ -1002,9 +1001,10 @@ sez.~\ref{sec:thread_xxx}). \const{WCONTINUED}& Ritorna anche quando un processo figlio che era stato fermato ha ripreso l'esecuzione.\footnotemark \\ \hline - \const{\_\_WCLONE}& Attende solo per i figli creati con \func{clone}, - vale a dire processi che non emettono nessun segnale - o emettono un segnale diverso da \const{SIGCHL} alla + \const{\_\_WCLONE}& Attende solo per i figli creati con \func{clone} + (vedi sez.~\ref{sec:process_clone}), vale a dire + processi che non emettono nessun segnale + o emettono un segnale diverso da \const{SIGCHLD} alla terminazione. \\ \const{\_\_WALL} & Attende per qualunque processo figlio. \\ \const{\_\_WNOTHREAD}& Non attende per i figli di altri \textit{thread} @@ -1455,9 +1455,8 @@ Le altre quattro funzioni si limitano invece a cercare di eseguire il file indicato dall'argomento \param{path}, che viene interpretato come il \itindex{pathname} \textit{pathname} del programma. -\begin{figure}[htb] - \centering - \includegraphics[width=12cm]{img/exec_rel} +\begin{figure}[!htb] + \centering \includegraphics[width=12cm]{img/exec_rel} \caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.} \label{fig:proc_exec_relat} \end{figure} @@ -2693,9 +2692,9 @@ priorità statica da assegnare al processo; lo standard prevede che questo debba essere assegnato all'interno di un intervallo fra un massimo ed un minimo che nel caso di Linux sono rispettivamente 1 e 99. -\begin{figure}[!bht] +\begin{figure}[!htbp] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\textwidth} \includestruct{listati/sched_param.c} \end{minipage} \normalsize @@ -3109,7 +3108,7 @@ di I/O.\footnote{se usate in corrispondenza ad uno scheduler diverso il loro utilizzo non avrà alcun effetto.} Dato che non esiste una interfaccia diretta nelle \acr{glibc} per queste due funzioni occorrerà invocarle tramite la funzione \func{syscall} (come illustrato in -sez.~\ref{sec:intro_syscall}). Le due funzioni sono \funcd{ioprio\_get} ed +sez.~\ref{sec:proc_syscall}). Le due funzioni sono \funcd{ioprio\_get} ed \funcd{ioprio\_set}; i rispettivi prototipi sono: \begin{functions} \headdecl{linux/ioprio.h} @@ -3297,50 +3296,154 @@ di essa in un secondo tempo. \label{sec:process_clone} La funzione tradizionale con cui creare un nuovo processo in un sistema -Unix-like è, come illustrato in sez.~\ref{sec:proc_fork}, \func{fork}, ma con +Unix-like, come illustrato in sez.~\ref{sec:proc_fork}, è \func{fork}, ma con l'introduzione del supporto del kernel per i \textit{thread} (vedi cap.~\ref{cha:threads}), si è avuta la necessità di una interfaccia che consentisse un maggiore controllo sulla modalità con cui vengono creati nuovi -processi, che poi è stata utilizzata anche per fornire ulteriore supporto per -le varie tecnologie di virtualizzazione dei processi (i cosidetti -\textit{container}). - -Per far questo l'interfaccia per la creazione di un nuovo processo è stata -implementata una nuova \textit{system call}, \texttt{sys\_clone}, che consente -di reimplementare anche la tradizionale \func{fork}. La \textit{system call} -richiede due argomenti, \param{flags}, che consente di controllare le modalità -di creazione del nuovo processo e \param{child\_stack}, che deve essere -indicato se si intende creare un \textit{thread} in cui la memoria viene -condivisa fra il processo chiamante ed il nuovo processo creato. L'esecuzione -del programma creato da \param{child\_stack} riprende, come per \func{fork}, -da dopo l'esecuzione della stessa. +processi, che poi è stata utilizzata anche per fornire supporto per le +tecnologie di virtualizzazione dei processi (i cosiddetti \textit{container}). + +Per questo l'interfaccia per la creazione di un nuovo processo è stata +delegata ad una nuova \textit{system call}, \func{sys\_clone}, che consente di +reimplementare anche la tradizionale \func{fork}. In realtà in questo caso più +che di nuovi processi si può parlare della creazioni di nuovi +``\textit{task}'' del kernel che possono assumere la veste sia di un processo +classico come quelli trattati finora, che di un \textit{thread}, come quelli +che vedremo in sez.~\ref{sec:linux_thread}, in cui la memoria viene condivisa +fra il processo chiamante ed il nuovo processo creato. Per evitare confusione +fra \textit{thread} e processi ordinari, abbiamo deciso di usare la +nomenclatura \textit{task} per indicare la unità di esecuzione generica messa +a disposizione del kernel che \texttt{sys\_clone} permette di creare. + +Oltre a questo la funzione consente, ad uso delle nuove funzionalità di +virtualizzazione dei processi, di creare nuovi \textit{namespace} per una +serie di proprietà generali dei processi (come l'elenco dei PID, l'albero dei +file, dei \textit{mount point}, della rete, ecc.), che consentono di creare +gruppi di processi che vivono in una sorta di spazio separato dagli altri, che +costituisce poi quello che viene chiamato un \textit{container}. + +La \textit{system call} richiede soltanto due argomenti: il +primo, \param{flags}, consente di controllare le modalità di creazione del +nuovo \textit{task}, il secondo, \param{child\_stack}, imposta l'indirizzo +dello \itindex{stack} \textit{stack} per il nuovo \textit{task}, e deve essere +indicato quando si intende creare un \textit{thread}. L'esecuzione del +programma creato da \func{sys\_clone} riprende, come per \func{fork}, da +dopo l'esecuzione della stessa. La necessità di avere uno \itindex{stack} \textit{stack} alternativo c'è solo quando si intende creare un \textit{thread}, in tal caso infatti il nuovo -processo vede esattamente la stessa memoria del processo chiamante, e nella -sua esecuzione andrebbe a scrivere sullo \textit{stack} usato anche da questi, -il che comporterebbe immediatamente la presenza di \itindex{race~condition} -\textit{race conditions} all'esecuzione di una funzione da parte di entrambi -(si ricordi quanto visto in sez.~\ref{sec:proc_mem_layout} riguardo all'uso -dello \textit{stack}). - -Per evitare questo è allora necessario che il chiamante allochi -preventivamente un'area di memoria (in genere lo si fa con una \func{malloc}) -che la funzione imposterà come \textit{stack} del nuovo processo, avendo -ovviamente cura di non utilizzarla direttamente. Si tenga presente inoltre che -in molte architetture lo \textit{stack} cresce verso il basso, pertanto in tal -caso non si dovrà specificare per \param{child\_stack} il puntatore restituito -da \func{malloc}, ma un puntatore alla fine del buffer con essa allocato. - -Dato che tutto ciò serve solo per i \textit{thread} che condividono la +\textit{task} vede esattamente la stessa memoria del \textit{task} +``\textsl{padre}'',\footnote{in questo caso per padre si intende semplicemente + il \textit{task} che ha eseguito \func{sys\_clone} rispetto al \textit{task} + da essa creato, senza nessuna delle implicazioni che il concetto ha per i + processi.} e nella sua esecuzione alla prima chiamata di una funzione +andrebbe a scrivere sullo \textit{stack} usato anche dal padre (si ricordi +quanto visto in sez.~\ref{sec:proc_mem_layout} riguardo all'uso dello +\textit{stack}). + +Per evitare di doversi garantire contro la evidente possibilità di +\itindex{race~condition} \textit{race condition} che questa situazione +comporta (vedi sez.~\ref{sec:proc_race_cond} per una spiegazione della +problematica) è necessario che il chiamante allochi preventivamente un'area di +memoria. In genere lo si fa con una \func{malloc} che allochi un buffer che +la funzione imposterà come \textit{stack} del nuovo processo, avendo +ovviamente cura di non utilizzarlo direttamente nel processo chiamante. In +questo modo i due \textit{task} avranno degli \textit{stack} indipendenti e +non si dovranno affrontare problematiche di \itindex{race~condition} +\textit{race condition}. Si tenga presente inoltre che in molte architetture +di processore lo \textit{stack} cresce verso il basso, pertanto in tal caso +non si dovrà specificare per \param{child\_stack} il puntatore restituito da +\func{malloc}, ma un puntatore alla fine del buffer da essa allocato. + +Dato che tutto ciò è necessario solo per i \textit{thread} che condividono la memoria, la \textit{system call}, a differenza della funzione di libreria che -vedremo a breve, consente anche di passare il valore \val{NULL} -per \param{child\_stack}, nel qual caso si applicherà la semantica del -\itindex{copy-on-write} \textit{copy on write} illustrata in -sez.~\ref{sec:proc_fork}, le pagine dello \textit{stack} verranno -automaticamente copiate come le altre e il nuovo processo avrà un suo -\textit{stack}. +vedremo a breve, consente anche di passare per \param{child\_stack} il valore +\val{NULL}, che non imposta un nuovo \textit{stack}. Se infatti si crea un +processo, questo ottiene un suo nuovo spazio degli indirizzi,\footnote{è + sottinteso cioè che non si stia usando il flag \const{CLONE\_VM}.} ed in +questo caso si applica la semantica del \itindex{copy-on-write} \textit{copy + on write} illustrata in sez.~\ref{sec:proc_fork}, per cui le pagine dello +\textit{stack} verranno automaticamente copiate come le altre e il nuovo +processo avrà un suo \textit{stack} totalmente indipendente da quello del +padre. + +Dato che l'uso principale della nuova \textit{system call} è quello relativo +alla creazione dei \textit{thread}, le \acr{glibc} definiscono una funzione di +libreria con una sintassi diversa, orientata a questo scopo, e la +\textit{system call} resta accessibile solo se invocata esplicitamente come +visto in sez.~\ref{sec:proc_syscall}.\footnote{ed inoltre per questa + \textit{system call} non è disponibile la chiamata veloce con + \texttt{vsyscall}.} La funzione di libreria si chiama semplicemente +\funcd{clone} ed il suo prototipo è: +\begin{functions} + \headdecl{sys/sched.h} + \funcdecl{int clone(int (*fn)(void *), void *child\_stack, int + flags, void *arg, ... \\ + /* pid\_t *ptid, struct user\_desc *tls, pid\_t *ctid */)} + + Crea un nuovo processo o \textit{thread} eseguendo la funzione \param{fn}. + + \bodydesc{La funzione ritorna al chiamante il \textit{Thread ID} assegnato + al nuovo processo in caso di successo e $-1$ in caso di errore, nel qual + caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\errcode{EAGAIN}] sono già in esecuzione troppi processi. + \item[\errcode{EINVAL}] si è usata una combinazione non valida di flag o + un valore nullo per \param{child\_stack}. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare una nuova + \struct{task\_struct} o per copiare le parti del contesto del chiamante + necessarie al nuovo \textit{task}. + \item[\errcode{EPERM}] non si hanno i privilegi di amministratore + richiesti dai flag indicati. + \end{errlist} + } +\end{functions} + +La funzione prende come primo argomento il puntatore alla funzione che verrà +messa in esecuzione nel nuovo processo, che può avere un unico argomento di +tipo puntatore a \ctyp{void}, il cui valore viene passato dal terzo +argomento \param{arg}; per quanto il precedente prototipo possa intimidire +nella sua espressione, in realtà l'uso è molto semplice basterà definire una +qualunque funzione \param{fn} del tipo indicato, e \code{fn(arg)} sarà +eseguita in un nuovo processo. + +Il nuovo processo resterà in esecuzione fintanto che la funzione \param{fn} +non ritorna, o esegue \func{exit} o viene terminata da un segnale. Il valore +di ritorno della funzione (o quello specificato con \func{exit}) verrà +utilizzato come stato di uscita della funzione. + +I tre argomenti \param{ptid}, \param{tls} e \param{ctid} sono opzionali e sono +presenti solo a partire dal kernel 2.6. + +Il comportamento di \func{clone}, che si riflette sulle caratteristiche del +nuovo processo da essa creato, è controllato dall'argomento \param{flags}, + +\begin{basedescript}{\desclabelstyle{\pushlabel}} + +\item[\const{CLONE\_CHILD\_CLEARTID}] +\item[\const{CLONE\_CHILD\_SETTID}] +\item[\const{CLONE\_FILES}] +\item[\const{CLONE\_FS}] +\item[\const{CLONE\_IO}] +\item[\const{CLONE\_NEWIPC}] +\item[\const{CLONE\_NEWNET}] +\item[\const{CLONE\_NEWNS}] +\item[\const{CLONE\_NEWPID}] +\item[\const{CLONE\_NEWUTS}] +\item[\const{CLONE\_PARENT}] +\item[\const{CLONE\_PARENT\_SETTID}] +\item[\const{CLONE\_PID}] +\item[\const{CLONE\_PTRACE}] +\item[\const{CLONE\_SETTLS}] +\item[\const{CLONE\_SIGHAND}] +\item[\const{CLONE\_STOPPED}] +\item[\const{CLONE\_SYSVSEM}] +\item[\const{CLONE\_THREAD}] +\item[\const{CLONE\_UNTRACED}] +\item[\const{CLONE\_VFORK}] +\item[\const{CLONE\_VM}] +\end{basedescript} \subsection{La funzione \func{prctl}} @@ -3353,7 +3456,7 @@ la cui gestione è stata predisposta una apposita \textit{system call} che fornisce una interfaccia generica per tutte le operazioni specialistiche. La funzione è \funcd{prctl} ed il suo prototipo è:\footnote{la funzione non è standardizzata ed è specifica di Linux, anche se ne esiste una analoga in - IRIX, è stata introdotta con il kernel 2.1.57.} + IRIX; è stata introdotta con il kernel 2.1.57.} \begin{functions} \headdecl{sys/prctl.h} @@ -3625,6 +3728,9 @@ predefinite del seguente elenco, che illustra quelle disponibili al momento: Da fare +% TODO: trattare PTRACE_SEIZE, aggiunta con il kernel 3.1 + + \subsection{L'accesso alle porte di I/O} \label{sec:process_io_port} @@ -3848,12 +3954,12 @@ varie funzioni di libreria, che sono identificate aggiungendo il suffisso % LocalWords: SIGKILL static RLIMIT preemption PREEMPT VOLUNTARY IDLE RTPRIO % LocalWords: completely fair compat uniform CFQ queuing elevator dev cfq RT % LocalWords: documentation block syscall ioprio IPRIO CLASS class best effort -% LocalWords: refresh semop dnotify MADV DONTFORK prctl WCLONE SIGCHL WALL big -% LocalWords: WNOTHREAD DUMPABLE KEEPCAPS IRIX CAPBSET endianess endian -% LocalWords: little PPC PowerPC FPEMU NOPRINT SIGFPE FPEXC point FP SW +% LocalWords: refresh semop dnotify MADV DONTFORK prctl WCLONE WALL big +% LocalWords: WNOTHREAD DUMPABLE KEEPCAPS IRIX CAPBSET endianess endian flags +% LocalWords: little PPC PowerPC FPEMU NOPRINT SIGFPE FPEXC point FP SW malloc % LocalWords: exception EXC ENABLE OVF overflow UND underflow RES INV DISABLED -% LocalWords: NONRECOV ASYNC KEEP securebits NAME NUL PDEATHSIG SECCOMP -% LocalWords: secure computing sigreturn TIMING STATISTICAL TSC MCE +% LocalWords: NONRECOV ASYNC KEEP securebits NAME NUL PDEATHSIG SECCOMP VM +% LocalWords: secure computing sigreturn TIMING STATISTICAL TSC MCE conditions % LocalWords: timestamp Stamp SIGSEGV UNALIGN SIGBUS MCEERR AO failure early %%% Local Variables: