support de cours - Florent Madelaine

publicité
05 - Processus
Florent Madelaine
[email protected]
ce cours suit très littéralement celui de Gaétan Richard
lui-même hérité de nombreux autres intervenants tempus
passim
L2 – S4 2014/2015
1. Présentation
Lancement
Rappel. Sur le disque, on dispose de fichiers contenant du code
exécutable. Pour pouvoir exécuter le code correspondant, il est
nécessaire de disposer du droit d’exécution (bit x).
Nous verrons le mécanisme permettant le lancement de nouveau
processus en détail plus loin.
1. Présentation
1 / 35
Mise en mémoire (dans la RAM)
Le processus dispose d’un espace d’adressage qui lui est propre,
alloué et initialisé lorsque le système charge puis exécute le
programme associé.
1. Présentation
2 / 35
Mise en mémoire (dans la RAM)
Le processus dispose d’un espace d’adressage qui lui est propre,
alloué et initialisé lorsque le système charge puis exécute le
programme associé.
Le processus ne peut donc pas voir l’espace mémoire des autres
processus.
1. Présentation
2 / 35
Mise en mémoire (dans la RAM)
Le processus dispose d’un espace d’adressage qui lui est propre,
alloué et initialisé lorsque le système charge puis exécute le
programme associé.
Le processus ne peut donc pas voir l’espace mémoire des autres
processus.
La mémoire du processus est organisée de manière standardisée
et contient en particulier :
I
le code binaire du programme exécuté par le processus ;
I
des données qui ne varient pas (variables globales) ; et,
I
lorsque le code est en cours d’exécution des données qui
évoluent puisqu’elles concernent le calcul en cours
(variables locales, appels en attente de fonctions, leurs
arguments etc).
1. Présentation
2 / 35
Mise en mémoire
L’organisation en mémoire d’un processus est représentée dans
la figure ci-dessous.
I
env, args : environnement ($HOME ...) et
arguments.
I
stack : la pile (appels, variables locales
etc)
I
heap : variables dont on ne connaı̂t pas
la taille en avance (tableau) ou grosses
données (image).
I
data : emplacement des variables
globales du programme
I
text : code binaire du programme.
env, args
stack
heap
data
text
1. Présentation
3 / 35
Méta-informations d’un processus
I
un propriétaire, un groupe ;
I
un identifiant (pid) ;
I
l’identifiant de son père (ppid) ;
I
une table des descripteurs de fichiers ;
I
des informations pour l’ordonnancement (priorité, . . . ) ;
I
des informations pour les ressources (limites) ;
I
une table des signaux reçus (cf cours sur les signaux) ;
I
...
1. Présentation
4 / 35
bit setuid / setgid
Pour déterminer les droits d’un processus, on regarde le
propriétaire et le groupe effectif . En général, ceux-ci sont les
mêmes que le propriétaire et groupe sauf en cas de bit setuid
ou setgid.
1. Présentation
5 / 35
Méta-informations du shell
Il est possible d’accéder à ces informations aux travers des
variables :
I
UID et GID contiennent l’identifiant de l’utilisateur et du
groupe ;
I
$ contient le PID ;
I
PPID contient le PID du père.
Il est également possible d’avoir accès à l’identifiant de
l’utilisateur par les commandes id et whoami.
Il est possible de changer le groupe d’un processus avec les
commandes su et sudo.
1. Présentation
6 / 35
Pour les autres processus
Il est possible d’obtenir les méta-informations des processus par
l’intermédiaire de la commande ps.
Il existe également la commande pstree qui permet d’afficher le
résultat sous forme d’un arbre.
Procfs : Sous Linux, ces informations sont également
accessibles par l’intermédiaire du système de fichiers monté
dans /proc. Chaque processus disposant d’un répertoire au nom
de son pid.
1. Présentation
7 / 35
Getpid and co
En python, il existe les fonctions pour récupérer ces
informations :
I
os.getpid(),
I
os.getppid(),
I
os.getuid(),os.geteuid(),
I
os.getgid(),os.getegid(),os.getpgid(pid)
Il est également possible de modifier ces valeurs (sous réserve
d’en avoir les droits) à l’aide des versions setuid,seteuid,
setegid, . . .
1. Présentation
8 / 35
2. États
États
En simplifiant, un processus peut être dans les états suivants :
nouveau
prêt
actif
zombie
en attente
Un processus peut également être envoyé dans le swap.
2. États
9 / 35
C’est quoi un processus Zombie ?
A definition from Wikipedia.
The term zombie process derives from the common
definition of zombie — an undead person. In the
term’s metaphor, the child process has ”died” but has
not yet been ”reaped”. Also, unlike normal processes,
the kill command has no effect on a zombie process.
2. États
10 / 35
C’est quoi un processus Zombie ?
A definition from Wikipedia.
The term zombie process derives from the common
definition of zombie — an undead person. In the
term’s metaphor, the child process has ”died” but has
not yet been ”reaped”. Also, unlike normal processes,
the kill command has no effect on a zombie process.
reap = harvest.
The grim reaper
2. États
10 / 35
Processus Zombie
Il s’agit normalement d’un processus qui a terminé son
traitement mais dont la valeur de retour n’a pas été lue.
2. États
11 / 35
Processus Zombie
Il s’agit normalement d’un processus qui a terminé son
traitement mais dont la valeur de retour n’a pas été lue.
Le processus qui doit lire cette valeur est son père (le processus
qui a lancé ce processus).
2. États
11 / 35
Processus Zombie
Il s’agit normalement d’un processus qui a terminé son
traitement mais dont la valeur de retour n’a pas été lue.
Le processus qui doit lire cette valeur est son père (le processus
qui a lancé ce processus).
Remarque.
Parfois, des processus restent longtemps des zombies : dans ce cas, il s’agit
a priori d’un problème.
Normalement, même si son père meurt, un processus (dit orphelin) est
rattaché au processus numéro 1 (init) qui est l’ancêtre de tous les processus.
2. États
11 / 35
C’est quoi le swap ?
Traditionnellement il s’agissait d’une partition sur le disque,
permettant de prétendre qu’on avait plus de RAM.
RAM (prétendue) = RAM + SWAP
Depuis que les ordinateurs ont beaucoup de RAM, le swap est
devenu plus ou moins désuet.
On peu dorénavant utiliser des fichiers swap, pas forcément des
partitions.
Une utilisation pour les portables : suspend-to-disk.
Attention. 6= suspend-to-RAM
Un peu d’anglais : swap = échanger.
2. États
12 / 35
Observer les processus
La commande top permet d’afficher les informations sur les
processus en cours d’exécution sur la machine. Il existe
également parfois des variantes plus évoluées de cette
commande (htop).
2. États
13 / 35
Limites
Il est possible et habituel d’imposer des limites sur les
processus. Ces limites peuvent prendre la forme :
I
du temps CPU utilisé ;
I
du nombre de fichiers ouverts ;
I
de la taille des fichiers ouverts ;
I
de la taille du tas et de la pile ;
I
du nombre de processus fils ;
I
...
Il existe deux types de limites :
2. États
I
les soft limits qui sont celles par défaut d’un processus créé ;
I
les hard limits qui sont celles maximales que l’utilisateur
peut fixer.
14 / 35
Manipulation des limites
Les limites en shell se manipulent à l’aide de la commande
ulimit.
En python, ces fonctionnalités sont disponibles par
l’intermédiaire du module resource et notamment des
fonctions :
2. États
I
resource.getrlimit(resource)
I
resource.setrlimit(resource, limits)
15 / 35
3. Ordonnancement
Principes
Un ordinateur possède un (ou quelques) processeur(s).
Chaque processeur peut être composé d’une ou plusieurs
unité(s) de calcul : les cœurs
Le système d’exploitation permet d’avoir évidement plus de
processus que juste le nombre de cœurs. Comme on l’a déjà
évoqué, il s’agit d’un système multi-tâches : sur chaque cœur on
donne l’illusion d’une exécution parallèle aux utilisateurs en
commutant rapidement entre différents processus.
Fonctionnement. Le système d’exploitation partage une unité
de calcul entre plusieurs processus, une gestion qu’on appelle
l’ordonnancement.
3. Ordonnancement
16 / 35
Découpage
Une fois le processus sur une unité de calcul, il existe plusieurs
cas dans lesquels le processus s’en sépare :
I
le processus s’arrête (devient zombie) ;
I
le processus le demande explicitement (sleep) ;
I
le processus est en attente (cas d’un appel système,
exemple : accès disque) ;
I
le système choisit d’arrêter le processus (système
préemptif).
Dans ce cas, le système d’exploitation détermine un nouveaux
processus à affecter à l’unité de calcul.
3. Ordonnancement
17 / 35
Modèles simples
Il existe plusieurs techniques pour déterminer comment affecter
les tâches aux unités de calculs. On choisit l’une ou l’autre en
fonction de l’utilisation.
I
FIFO : on affecte dans l’ordre d’apparition ;
I
Round Robin : on effectue un bloc de chaque processus à
tour de rôle ;
I
Priorité : chaque processus dispose d’une valeur de
priorité et on choisit le processus de plus forte priorité à
chaque fois.
3. Ordonnancement
18 / 35
Modèle évolués
Le modèle actuel dans la plupart des systèmes d’exploitation
est basé sur les principes suivants :
I
chaque processus possède une priorité de base ;
I
cette priorité augmente quand le processus est inactif et
diminue quand il est actif (le taux de changement dépend
de la priorité de base) ;
I
le système choisit parmi les processus de plus forte priorité.
3. Ordonnancement
19 / 35
Nice
Sous UNIX, il est possible de changer la priorité de base d’un
processus. Cette valeur est comprise entre −20 et 20 (plus le
nombre est bas, plus la priorité est grande). Le défaut est 0.
Il est toujours possible de diminuer la priorité d’un processus,
l’augmentation demande des droits particuliers (root).
Avec le shell, il est possible d’effectuer ces opérations à l’aide
des commandes nice au lancement et renice durant l’exécution.
Sous python, cette fonctionnalité est accessible par l’appel
système : os.nice(increment).
3. Ordonnancement
20 / 35
Sleep / yield
Un processus peut demander à dormir pendant un certain
temps à l’aide de la commande sleep.
En python, cette fonctionnalité est accessible par la commande
time.sleep(secs).
En python, il existe aussi le mot-clé yield qui permet
d’interrompre une fonction. Il est alors possible de la reprendre
à l’aide de la méthode .next().
3. Ordonnancement
21 / 35
Exemple
def yrange(n):
i = 0
while i < n:
yield i
i += 1
3. Ordonnancement
22 / 35
Exemple
def yrange(n):
i = 0
while i < n:
yield i
i += 1
>>> y = yrange(3)
>>> y
<generator object yrange at 0x401f30>
>>> y.next()
0
>>> y.next()
1
>>> y.next()
2
>>> y.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
3. Ordonnancement
22 / 35
4. Manipulation
Duplication de processus
Le seul moyen de créer un nouveau processus est de dupliquer
un processus existant. Cette opération est réalisé à l’aide de
l’appel système fork.
p (pid=13)
père (pid=13)
4. Manipulation
fils (ppid=13)
23 / 35
En python
La fonction os.fork() permet de dupliquer des processus.
La fonction renvoie :
I 0 pour le fils ;
I le pid du fils pour le père.
Exemple :
from os import *
swith fork():
case 0:
... fils ...
exit 0
else:
... père ...
4. Manipulation
24 / 35
Recouvrement
Pour lancer un autre programme, la méthode consiste à
remplacer le programme courant par un autre : le
recouvrement.
Ceci s’effectue à l’aide de l’appel système exec.
p
exec
p’
4. Manipulation
25 / 35
En python
Il existe différentes versions suivant que l’on souhaite donner les
arguments un à un (l) ou sous forme de tableau (v) ; que l’on
souhaite avoir l’environnement en argument (e) ; ou que l’on
souhaite chercher dans le path (p).
os.execl(path, arg0, arg1, ...), os.execle(path, arg0,
arg1, ..., env), os.execlp(file, arg0, arg1, ...),
os.execlpe(file, arg0, arg1, ..., env), os.execv(path,
args), os.execve(path, args, env),
os.execvp(file, args), os.execvpe(file, args, env)
Exemple :
...
os.execlp("monscript.sh", "monscript.sh", "arg1")
... jamais atteint ...
4. Manipulation
26 / 35
Fin d’un processus
Pour terminer un processus, il est possible de sortir à l’aide de
la fonction exit. Cette fonction prend un entier en argument.
Le processus devient alors un zombie.
Cette valeur peut-être récupérée par le père à l’aide de la
commande wait qui attend au besoin la fin d’un processus. Le
processus zombie correspondant est alors définitivement détruit.
père
fils
exit
wait
4. Manipulation
27 / 35
En python
Il existe plusieurs versions de wait selon les options que l’on
souhaite :
I
os.wait() ;
I
os.waitpid(pid, options) ;
I
os.wait3([options]) ;
I
os.wait4(pid, options) ;
4. Manipulation
28 / 35
Orphelins
Principe : tout processus possède un père.
Exception : le premier processus (init) n’a pas de père.
Orphelin : quand le père d’un processus meurt, soit celui-ci est
détruit ; soit, il reste en vie et est alors récupéré par init.
4. Manipulation
29 / 35
Fonctionnement en shell
En shell, chaque commande lancée effectue un fork et un exec
de la commande. Il attend ensuite la fin de l’exécution de la
commande.
fork
exec
exit
wait
4. Manipulation
30 / 35
Sous-shell et arrière plan
Il est possible de lancer un sous-shell en utilisant les
parenthèses. Les commandes sont alors réalisées dans un
processus fils du shell.
Il est aussi possible de lancer une commande en arrière-plan
en ajoutant le symbole & à la fin d’un commande. Dans ce cas,
le shell n’attend pas la fin de l’exécution (pas de wait).
4. Manipulation
31 / 35
5. Threads
Remarques sur les processus
Lors de l’utilisation d’un fork, on doit dupliquer physiquement
les méta-données du processus ainsi que sont contenu.
Les deux processus obtenu sont donc complètement
indépendants.
Note. Dorénavant, de nombreux systèmes d’exploitations
utilisent du copy on write qui permet d’éviter le copie physique
de la mémoire tant que cela n’est pas nécessaire.
5. Threads
32 / 35
Principe
Dans certains cas, on souhaiterait disposer du parallélisme sans
avoir recours à la lourdeur des processus.
Pour ce cas, il existe des threads (processus légers) qui
permettent d’effectuer du parallélisme à l’intérieur d’un même
processus.
Dans ce cas, on a deux unités en train de s’exécuter qui
partagent la même mémoire.
5. Threads
33 / 35
En python
En python, il existe le module threading permet de gérer les
threads.
La création se fait à l’aide du constructeur :
threading.Thread(group=None, target=None,
name=None, args=(), kwargs={}).
Il est ensuite possible de manipuler ces éléments de façon
similaire au processus.
5. Threads
34 / 35
Chercher les problèmes
Comme la mémoire est partagée, les threads posent de
nombreux problèmes de concurrence. Ceci fera l’objet d’un
cours par la suite.
La combinaison usuelle est de d’abord faire des fork et ensuite
des threads. Utiliser les deux en même temps demande une
bonne réflexion pour comprendre les comportements obtenus
(lorsque ceux-ci ne sont pas buggés).
5. Threads
35 / 35
Téléchargement