Multitâche et politiques d’ordonnancement sous Linux

I. Présentation

Le multitâche a joué (et joue encore !) un rôle primordial dans l’évolution des machines et des systèmes d’exploitation. En effet, il a permis d’augmenter considérablement la capacité de traitement d’un système concernant les différentes tâches qu’il se doit de gérer. Au final, la réactivité du système d’exploitation se voit grandement améliorée.

L’une des fonctionnalités principale du noyau Linux, et plus particulièrement de la partie appelée le « Scheduler » ou Ordonnanceur et de gérer la partie multitâche du système d’exploitation, appelée aussi « multitâche préemptif ». Les fonctionnalités principales de l’ordonnanceur d’un noyau Linux est d’élire un processus parmi d’autres qui occupera le processeur pendant un temps donné avant qu’il ne soit préempté au profit d’un autre processus. Ce choix est fait selon la politique d’ordonnancement appliquée et aussi suivant plusieurs critères de sélection personnel à chaque processus dont par exemple la priorité qu’ils ont reçus.

scheduler1

La configuration de l’ordonnanceur à travers les différentes politiques d’ordonnancement et des priorités respectives est extrêmement critique. Un programmeur distrait qui possède des privilèges augmentés sur le système peut par inadvertance bloquer tout le système. Nous verrons avec un premier exemple ci-dessous à quel point l’ordonnanceur est considéré comme l’une des pièces maitresse d’un système d’exploitation.

II. Problème

Pour comprendre l’activité d’un scheduler et la criticité de ses choix d’ordonnancement, exécutons se programme sur une machine monoprocesseur soit avec les privilèges root ou en activant le bit SUID root du programme :

Note : L’activation du bit SUID nous permet d’exécuter un programme avec l’UID effectif du propriétaire du programme, dans notre exemple root, sans être effectivement logué en tant que ce dernier.

Exemple : Si on est l’utilisateur user1 et qu’on exécute le programme mon_programme avec le bit SUID root activé, mon_programme  s’exécutera sous l’identité effective de root et donc avec les privilèges de celui-ci. L’activation du bit SUID se fait sur le programme généré après la compilation avec la commande ci-dessous :

chmod u+s mon_programme
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
int main(){
struct sched_param parametres;
parametres.sched_priority = 12;
if(sched_setscheduler(getpid(),SCHED_RR,parametres)!=0){
fprintf(stdout,”Impossible de changer la politique d’ordonnancement \n”);
exit(EXIT_FAILURE) ;
}
while(1){
fprintf(stdout,”Je suis en plein execution \n”);
}
return EXIT_SUCCESS;
}

On compile avec la commande suivante :

gcc –o mon_programme mon_programme.c

Et on exécute avec : ./mon_programme

Résultat…tout est figé ! L’interface graphique ne répond plus ! Aucune action n’est possible.

III. Explications

Ce phénomène s’explique très facilement, néanmoins, Il faut tout d’abord comprendre quelques principes élémentaires sur les états transitoires d’un processus ainsi que les politiques d’ordonnancement auxquelles il est soumis.

Tout d’abord :

A. Les cinq états d'un processus

Un processus passe pendant sa durée de vie par cinq états :

  • Ready : Cet état correspond à un processus qui est prêt à s’exécuter mais ne peut pas encore prendre possession du processeur car celui-ci est déjà pris par un autre processus.
  • Running : En état d’exécution, donc en pleine possession du processeur.
  • Stopped : Le processus a reçu un signal qui l’a stoppé.
  • Sleeping : Endormi, en attente d’un évènement, comme la fin d’une entrée sortie (écriture sur un terminal, …).
  • Zombie : Un processus père crée des processus fils à travers un fork. Le processus fils termine son exécution, mais le père n’en ai pas encore conscient. Le processus fils se retrouve dans un état zombie, inerte, mais occupe toujours une place dans la table de processus du système.

scheduler2

B. Les politiques d'ordonnancement

Le noyau Linux, spécialement le Scheduler adopte trois politiques d’ordonnancement pour gérer l’exécution des processus par le système :

SCHED_FIFO : FIFO pour First In First Out, premier arrivé premier servit. Dans cette politique, plusieurs files d’attente de processus sont créés chacune avec une priorité différente. Le processeur est affecté en priorité au premier processus qui le demande et ne le relâchera que lorsque :

1-Il aura fini de s’exécuter.
2-Stopper.
3-Endormi en attente d’un évènement.

Ce processus doit évidemment faire partie de la file d’attente de plus haute priorité. Lorsque le processus relâche le processeur, celui-ci sera affecté au processus suivant qui est à l’état Prêt et dans la même file d’attente s’il y’en a un, sinon le Scheduler en choisit un autre dans la file d’attente de priorité inférieur.

SCHED_RR : Symétrique à SCHED_FIFO en tout point sauf qu’ici chaque processus se voit attribuer une tranche de temps d’exécution qu’il ne pourra pas dépasser. A la fin de cette tranche de temps, il est relégué à la fin de ça file d’attente et le processeur sera réquisitionné pour un autre processus qui est à l’état Prêt et de même priorité. Si un tel processus n’existe pas, un autre de priorité inférieur est sélectionné.

SCHED_OTHER : Correspond à la politique par défaut du noyau Linux, les processus se voit attribuer dès leurs création une priorité dite « statique » qui peut être modifié via des appels systèmes. Avec cette priorité statique et en prenant en compte plusieurs autres facteurs, une priorité « dynamique » est calculée et en fonction de cette dernière le scheduler choisi un processus et lui attribue le processeur pour un temps d’exécution maximal.

Les processus sous les politiques SCHED_FIFO et SCHED_RR sont considérés comme des processus « temps réel » et sont donc plus prioritaires par rapport aux processus qui sont sous la politique par défaut SCHED_OTHER. Pourquoi ? Car le domaine de priorité des processus temps-réel est par définition augmenté par rapport au processus par défaut.

En résumé : Le processeur sera toujours attribué en priorité aux processus temps réel (SCHED_FIFO et SCHED_OTHER).

Tout ça pour revenir à notre exemple !

Dans notre programme, avec sched_setscheduler(getpid(),SCHED_RR,parametres) on a modifié la politique d’ordonnancement du processus appelant par une politique SCHED_RR qui est donc prioritaire aux autres processus du système qui sont, par défaut régis par une politique SCHED_OTHER. Le processus prend donc le processeur et ne le relâche pas pénalisant lourdement tous les autres processus s’exécutant avec la politique par défaut SCHED_OTHER incluant le processus gérant l’environnement graphique et son rafraichissement, à savoir X11. C’est pour cela que tout est bloqué y compris le pointeur de souris.

IV. Prévention

Des cas pareils sont essentiellement causés par des fautes de programmation ou un manque de vigilance d’un programmeur.

La modification des options d’ordonnancement demande d’avoir des droits suffisants. Ce qu’on peut préconiser donc dans de telle situation c’est :

A - D’éviter d’activer a tout va le bit SUID sur des programmes, essentiellement les plus critiques. On peut aussi désactiver cette option sur des programmes déjà installés (certains programmes doivent rester avec le bit SUID activé, comme la commande /usr/bin/passwd qui permet à n’importe quel utilisateur de changer son mot de passe). On peut rechercher de tels fichiers sur un système de fichier avec la commande ci-dessous :

# find / \( -perm -4000 -o -perm -2000 \) -exec ls –l {} \ ;

On peut modifier le bit SUID d’un programme avec :

# chmod u-s mon_programme

Ou dans le cas du bit SGID :

# chmod g-s mon_programme

B - D’éviter de programmer en étant connecté sous root.

C - Modifier le serveur X11 et donc l’environnement graphique pour qu’il puisse fonctionner en ordonnancement temps-réel avec une priorité élevée. Dans ce cas on peut toujours exécuter un autre terminal graphique d’où on pourra tuer un éventuel processus en boucle et qui pénalise tous les autres processus comme dans notre exemple.

Dans tous les cas, la vigilance du programmer est comme même nécessaire.

On est loin d’avoir vu tout le potentiel de la gestion de l’ordonnancement de processus mais néanmoins, après c’est quelques lignes, on se rend bien compte à quel point cette tâche est critique pour un système. A manipuler donc avec une grande précaution.

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.