Liens utiles

Consignes

Ce TP donnera lieu à une évaluation. Vous pouvez travailler en binômes.

Estimation du temps (optimiste)

Envoyer votre TP

Votre TP devra être envoyé par email à votre enseignant (Pierre.Hyvernat@univ-savoie.fr, Florian.Hatat@univ-savoie.fr ou Thomas.Seiller@univ-savoie.fr). Le sujet de votre mail doit contenir la chaîne "info524".

Vous devez envoyer une unique archive tar contenant :

points importants :

  1. votre archive doit contenir un répertoire, pas seulement des fichiers en vrac. Mon répertoire de travail s'appelle "Pierre_Hyvernat-TP2" ; pour créer l'archive, la ligne de commande est :

    $ tar cvf Pierre_Hyvernat.tar Pierre_Hyvernat/
    
  2. tous vos fichiers doivent commencer par un entête contenant vos noms et prénoms, ainsi que votre filière.

Si ces consignes ne sont pas respectées, l'enseignant se réserve le droit de vous enlever 5 points (ou même plus) sur la note finale.

Utiliser l'image fournie

L'archive fournie pour ce TP contient une image QEMU avec un MINIX déjà installé et configuré.

Pour l'utiliser, il suffit de télécharger l'image dans le répertoire /tmp et la décompresser :

$ cd /tmp/
$ mkdir TP2-OS
$ cd TP2-OS
$ wget http://lama.univ-savoie.fr/~hyvernat/Enseignement/1112/info524/minix.img.bz2
$ bunzip2 minix.img.bz2

Pour démarrer MINIX :

$ qemu -localtime -net user,hostfwd=tcp::2232-:22  -net nic,model=rtl8139 \
       -m 256 -drive if=ide,media=disk,cache=writeback,file=minix.img

Le mot de passe pour l'utilisateur root est root, et le mot de passe pour l'utilisateur etu est etu. Pour ce TP, vous n'avez pas besoin du compte administrateur. (Sauf si vous voulez installer votre propre version de malloc() dans le système lors de la dernière question.)

Transfert de fichiers

La méthode la plus simple pour transférer des fichiers entre la machine Linux hôte et la machine virtuelle MINIX est d'utiliser ssh. L'image de MINIX fournie contient un serveur ssh et la commande QEMU donnée permet de rediriger le port 2232 de l'hôte vers le port ssh habituel (port 22) de la machine virtuelle MINIX.

Ainsi, si vous faite un

$ ssh -p 2232 etu@localhost

à partir de la machine hôte, vous pouvez vous connecter sur le compte "root" de la machine MINIX. (L'inverse serait également possible si on redirigeait un port de la machine virtuelle sur le port 22 de votre machine...)

Vous pouvez vous servir de ça pour transférer facilement des fichiers :

$ scp -P 2232 fichier_linux etu@localhost:fichier_minix

dans la machine hôte pour copier un fichier de l'hôte vers la machine virtuelle, ou

$ scp -P 2232 etu@localhost:fichier_minix fichier_linux

dans la machine hôte pour copier un fichier de la machine virtuelle vers l'hôte.

1. Modèle mémoire des processus sous MINIX (et Linux)

Sous MINIX, la mémoire (virtuelle) de chaque processus est divisée en trois parties (« segments ») indépendants :

  1. le segment text (texte) contenant le texte (ie code exécutable) du programme,
  2. le segment stack (pile d'exécution) contenant les données de taille fixe du programme, les arguments de la fonction en cours d'exécution, ...
  3. le segment data (tas) contenant les données de taille dynamique du programme.

1.1. Afficher des adresses

  1. Écrivez un programme C adresses.c qui :
    • affiche quelques adresses appartenant au segment data,
    • affiche quelques adresses appartenant au segment stack.

    $ cc -com adresses.c -o adresses
    $ ./adresses
    Dans le segment "D"ata
    ======================
      - 0x....
      - 0x....
    
    Dans le segment "S"tack
    =======================
      - 0x....
      - 0x....
    
  2. Essayez d'afficher une adresse du segment text.
  3. Est-ce que les adresses affichées sont des adresses virtuelles ou physiques ?
  4. Où sont allouées
    • les variables globales,
    • les variables locales,
    • les arguments des fonctions,
    • les tableaux statiques (int tab[100];),
    • les tableaux dynamiques (int *t = malloc(sizeof(int)*taille);),
    • la fonction main(),
    • les autres fonctions,
    • ...
    Modifiez votre programme adresses.c pour afficher tout ces types d'adresses.
  1. L'option -com de la ligne de compilation permet de s'assurer que le segment text et les segments data et stack soient dans des espaces d'adressage communs. Par défaut, le segment text utilise un espace d'adressage disjoint.
  2. Le programme adresses.c doit être du C valide et n'utiliser que des fonctions standards. (Pas besoin d'inclure des fichiers systèmes...) Par exemple, l'entête de mon propre fichier ne contient que

    #include <stdio.h>
    #include <stdlib.h>
    

1.2. Allouer de la mémoire aux processus

Préliminaires

Chaque processus peut, à tout moment, réclamer une portion de mémoire dans son tas (segment D) grâce à la fonction "malloc()". Cette fonction ne fait pas partie du noyau du système d'exploitation mais utilise des fonctions bas niveau ("brk()" et "sbrk()"). "malloc()" est une fonction de la bibliothèque standard du langage C et elle fait partie de la norme POSIX, alors que "brk()" et "sbrk()" n'en font pas partie.

La fonction est définie dans le fichier /usr/src/lib/libc/ansi/malloc.c.

"malloc(s)" va essayer d'allouer un bloc de s octets dans le tas. S'il y a déjà une zone libre suffisamment grande, elle est utilisée. On peut utiliser l'algorithme First-Fit par exemple pour la découvrir. Si aucune zone libre suffisamment grande n'est trouvée, "malloc()" va utiliser la fonction "brk()" qui permet d'agrandir le tas. (Bien entendu, s'il n'y a plus de mémoire disponible, "brk()" va échouer, ainsi que "malloc()".)

Points importants :

-

Créez un fichier tests.c avec quelques fonctions en C qui créent des zones de mémoire et les libèrent, et vérifier que l'allocation de MINIX est bien un "FIRST FIT" avec une fonction dédiée.

Comprendre comment fonctionne l'allocation

L'archive contient un malloc-comment.c. Ouvrez le fichier et commentez la fonction malloc pour expliquer ce qu'elle fait. (C'est une étape préliminaire à la question suivante...)

Remarques :

Afficher les blocs

Bonus

Écrivez une fonction alloc_info() pour afficher la liste des bloc, la liste des blocs libre, leurs tailles, etc.

Pour tester votre fonction, le plus simple est de recopier les fichiers malloc-debug.{c,h} dans le répertoire TP2. Vous pourrez ainsi compiler uniquement votre fichier malloc.c (ou malloc-comment.c) et le tester sur un petit programme. Il faudra pour ceci ajouter un fichier malloc.h que vous inclurez à la place de stdlib.h. Pour forcer votre exécutable à utiliser votre version de malloc(), il faudra faire l'édition de liens avec votre fichier malloc.o.

Je vous conseille de faire un Makefile pour vous simplifier la vie. Et pour les fainéants, voici une archive tar...

ATTENTION : votre fichier malloc.c ne peut pas utiliser lui même la fonction malloc ou des fonctions qui l'utilisent indirectement (comme la fonction printf). Si vous voulez faire de l'affichage pour déboguer, je vous conseille d'utiliser uniquement les fonctions définies dans le fichier affiche.c (avec le fichier affiche.h correspondant).

Modifier l'allocateur

La version MINIX de "malloc()" utilise un algorithme First-Fit pour chercher une zone libre. Modifier le fichier malloc.c pour avoir une recherche Worst-Fit ou Next-Fit. (au choix)

Une fois que vous avez testé sur des programmes jouets, vous pouvez essayer sur des programmes plus conséquents, voir carrément en remplaçant la version standard par la votre. Ainsi, tous les appels à malloc utiliseront votre version !