Projet système PC : 2014 - FARAMAZ Gaetan, PERRIN Victor, VOURLAT Norman

De Ensiwiki
Aller à : navigation, rechercher
Claquos.png
Titre du projet Claqu'OS
Cadre Projet Système d'Exploitation 2014
Page principale Projet_système

Équipe Gaetan Faramaz Victor Perrin Norman Vourlat
Encadrants Damien Dejean Gaëtan Morin Grégory Mounié,


Présentation générale

Objectifs

L'objectif de ce projet est la réalisation d'un système d'exploitation pour PC très simplifié. Il permet d'aborder une grande partie des concepts vu en cours de SEPC durant la deuxième année d'apprentissage et de faire quelques rappels sur les cours d'architecture de première année.

Cahier des charges

Les spécifications précises du projet peuvent être consultées sur cette page : Projet système : spécification.

Etant apprentis, la gestion de la mémoire virtuelle était facultative pour nous et les files de messages remplacées par des sémaphores.

Gestion de projet

Git

L'utilisation du dépot git fourni par l'école est obligatoire. Nous avons utilisé le système de branches pour les différentes fonctionnalités, les branches portaient le nom de leur utilisateur principal (celui devant réalisé cette fonctionnalité).

Une fois arrivé au mode utilisateur, nous avons créé une nouvelle branche "usermode" pour commencer à travailler dessus sans risquer de perdre notre code fonctionnel.

Diagramme prévisionnel

Un diagramme prévisionnel et un effectif sont demandés pour le projet. Voici notre diagramme prévisionnel :


Diagramme prévisionnel

Diagramme effectif

Notre diagramme effectif est beaucoup plus précis que le prévisionnel (et différent) car nous n'avions pas une connaissance précise des différentes étapes avant de commencer le projet :


Diagramme effectif

Trello

Afin de faciliter la gestion de projet, nous avons utilisé l'outil Trello [1]. L'un des membres de notre groupe l'ayant déjà utilisé et l'interface étant très intuitive, sa prise en main a été très simple. Chacun a donc créé ses différentes taches à faire et les géraient en fonction de son avancement, permettant à tout le monde de suivre les travaux effectués lorsque l'on travaillait séparément (le week end par exemple). Voici une capture d'écran de notre board Trello en cours de réalisation du projet :

Board Trello

Coding style

Le coding style adopté pour notre projet est très classique, basé sur celui du kernel linux [2]. La seule particularité que nous avons vraiment défini entre nous était la façon de commenter notre code :

  • Sauf cas particulier, on ne met aucun commentaire dans une fonction mais on explique au dessus (avec des commentaires multi-lignes) qu'est ce qu'elle fait et comment.
  • Les fonctions sont commentées dans les fichiers .h si elles sont présentes, sinon directement dans le .c.
  • Dans le cas d'un code très complexe et difficilement compréhensible, on peut rajouter des commentaires dans une fonction.

Dans un soucis d’accessibilité nous avons choisi de coder et d'écrire nos commentaires uniquement en anglais.

Réalisation

Gestion de l'affichage à l'écran

Cette fonctionnalité correspond à la séance 1 de PSE : 4MMPS_Ecran. Le but est de permettre la gestion de l'affichage à l'écran, entre autre par l'appel à la fonction printf. Pour cela, nous avons implémenter diverses fonctions réalisant les fonctionnalités suivantes :

  • Effacage de l'écran
  • Défilement (une ligne à la fois)
  • Traitement des caractères spéciaux (retour à la ligne, tabulation, etc)
  • Placement du curseur là où le prochain caractère sera écrit
  • Ecriture d'un caractère à l'endroit demandé (coordonnée sous forme : ligne, colonne)

Toutes ces fonctions sont utilisées par la primitive système console_putbytes, elle même utilisée par printf pour afficher à l'écran.

Horloge

Cette fonctionnalité consiste à gérer les interruptions de l'horloge. Le rendu final revient à afficher à l'écran le temps passé depuis le lancement du système. Elle correspond à la séance 2 de PSE : 4MMPS_PIT.

Un traitant d'interruption est fournie avec les sources, nous avions donc juste à créer la fonction appelé par ce traitant. Pour faire simple, à chaque tour d'horloge le traitant appelle cette fonction, elle doit donc s'occuper de mettre à jour l'affichage du temps (en fonction de la fréquence de l'horloge).

Une fonction init_clock a aussi été créée permettant au noyau d'initialiser la fréquence de l'horloge au démarrage du système.

Processus et changement de contexte

Cette fonctionnalité consiste à gérer le basculement entre différents processus s’exécutant et correspond à la séance 3 de PSE : 4MMPS_Processus. On crée ici un nombre de processus défini statiquement et les fait fonctionner l'un après l'autre (sans priorité ou autre, en FIFO) ce qui n'est pas le cas dans le rendu final du projet.

Un fichier d'assembleur gérant le changement de contexte (context_switch) était fourni dans les sources. Le travail principal consistait donc à implémenter la structure du processus et la fonction schedule gérant le passage d'un processus à l'autre (faisant donc appel à context_switch).

Ordonnanceur

Cette fonctionnalité consiste à gérer le changement de processus. Les spécifications sont un ordonnanceur à priorité basique : on exécute toujours le processus de plus haute priorité. L'ordonnanceur est appelé à chaque interruption de l'horloge et dans toutes les fonctions modifiant les processus.

Processus "complexes"

Le système gère des processus plus complexe que ce qui a été décrit plus haut. Voici les quelques fonctionnalités demandées par les spécifications et réalisées au cours du projet :

Création dynamique

Lors de la création d'un processus, on peut choisir la taille de pile qu'on veut lui allouer. La pile est donc dynamique et non statique.

Terminaison

Un processus peut se terminer de plusieurs manières :

  • Ret : le processus a fini de s’exécuter et appelle la fonction ret qui le supprime et renvoie sa valeur de retour
  • Exit : Le processus fait appel à l'instruction exit pour se terminer, avec une valeur de retour
  • Kill : Un processus fait appel à la primitive système kill (avec le pid d'un processus) pour tuer un processus en cours d’exécution qui sera donc supprimé. Les processus peuvent se tuer eux même pour se terminer ("suicide").

Filiation

Un processus peut créer d'autres processus, il est donc le père de ces processus, qui sont ses fils. La gestion de filiation revient principalement à gérer le waitpid. Cette primitive système permet à un processus d'attendre que l'un de ses processus fils termine. Il peut soit attendre n'importe lequel (le premier qui se terminera donc), soit un en particulier en précisant son pid. Le processus père est donc "endormi" (retiré de la liste des processus exécutables) et ne sera réveillé qu'à la terminaison du fils attendu.

Cette primitive met aussi en jeu l'état zombie d'un processus. Un processus se terminant ne peut pas être supprimé si il a toujours un père actif (puisque son père va peut être vouloir l'attendre via waitpid). Il est donc retiré de la liste des exécutables (ready) et son état passe à zombie. Dès que son père l'a attendu ou qu'il se termine, on supprimera réellement ce processus.

Endormissement

Un processus peut faire appel à la primitive système wait_clock via la fonction sleep. Il est ensuite endormi pour le temps passer en paramètre et ne sera exécuté à nouveau qu'une fois ce temps écoulé (au minimum). En pratique, la primitive wait_clock prend en paramètre le numéro de l'instruction d'horloge à laquelle le processus doit se réveiller. Ce numéro correspond au nombre de tour d'horloge fait depuis le démarrage du système, il est donc facilement calculable à partir du temps d'endormissement voulu.

Sémaphores

Les spécifications pour les apprentis imposent la gestion des sémaphores pour la communication entre processus. Voici donc les fonctionnalités que nous avons implantés :

  • wait/signal : correspond au p et v des sémaphores
  • try_wait : permet à un processus de tester s'il peut prendre un sémaphore. Le prend si possible, sinon renvoie une erreur (mais ne bloque pas le processus).
  • signaln : équivalent à faire n fois signal sur un sémaphore
  • screate/sdelete : création et suppression de processus. La suppression libère tous les processus qui était bloqué sur ce sémaphore.
  • scount : permet de lire la valeur du compteur d'un sémaphore
  • sreset : permet de changer la valeur du compteur d'un sémaphore. Libère tous les processus bloqués sur ce sémaphore

A noter que lorsqu'on libère un processus bloqué, on choisit celui ayant la plus forte priorité et non celui qui attend depuis le plus longtemps.

Pilote clavier

Au niveau de la gestion d'entrée/sortie, on se limite au clavier. Le système gère les interruptions provoquées par l'appuie (et le relâchement) d'une touche du clavier. On traite le scancode envoyé par cette interruption et le gère en fonction. En bref, le pilote enregistre chaque caractère dans un buffer en attendant qu'on vienne lire ce buffer. Certaines touches particulières sont gérées (voir dans la partie suivante).

Console

Au démarrage, une console est démarrée pour permettre à l'utilisateur d’interagir avec le système. Le pilote clavier est utilisé ici pour la console. Si le mode echo est activé, chaque caractère entré est affiché sur l'écran. Certaines touches particulières sont aussi gérées :

  • Flèches droites et gauches pour déplacer le curseur sur le texte affiché
  • Flèches hautes et basses pour parcourir l'historique des dernières commandes entrées
  • Backspace pour effacer le caractère précédent le curseur
  • Ctrl + C pour arrêter l'éxécution de la commande en cours
  • Touche entrée pour envoyer une commande

Tant qu'on entre des caractères "classiques", ceux ci sont ajoutés au buffer. Lors de l'appuie sur la touche entrée, on traite la chaîne de caractère et lance la commande correspondante (le cas échéant). Si le buffer est plein, les caractères entrés ne sont ni affichés ni ajoutés au buffer.

Interpréteur de commande

La suite logique d'une console est d'implémenter un interpréteur capable d’exécuter les commandes entrées par l'utilisateur. Notre système gère les commandes suivantes :

  • help : affiche la liste des commandes disponibles (sauf celle ci)
  • ps : affiche les processus existants sur le système
  • sinfo : affiche la liste des sémaphores existants sur le système
  • sleep time : endort le processus pendant time secondes
  • clear : efface l'écran de la console
  • claquos : affiche le prompt de démarrage avec le logo de Claqu'OS
  • test nb : lance le test nb, si aucun argument n'est rentré, lance tout les tests à la suite

Problèmes rencontrés

N'étant que peu habitué à son utilisation, nous avons eu quelques problèmes avec l'outil Git, principalement lors de merge et des résolutions de conflits. Nous n'avons peut être pas assez réfléchi à la division du travail en fonction des fichiers et fonctionnalités affectés.

Nous avons aussi eu un peu de mal à comprendre la documentation du projet. Les informations étant un peu dispersées sur les différents pages liées au projet, il était parfois difficile de bien comprendre ce qui était demandé (par exemple, le fait que les sémaphore libèrent le processus le plus prioritaire et non celui qui attend depuis le plus longtemps, pareil pour la taille minimum des piles dynamiques). Nous avons donc perdu un certain temps à bloquer sur des bugs liés à une incompréhension sur l'implémentation demandé, surtout lors du passage des tests.

Un autre problème de compréhension a été sur le pilote clavier et l'utilisation de la fonction cons_read. Nous pensions au départ que cons_read devait gérer le buffer clavier et non pas simplement afficher la chaîne passer en paramètre. De même, l'utilisation de do_scancode n'est pas très claire.

Difficultés rencontrées

La plus grosse difficulté a été le passage au mode utilisateur ainsi que la gestion de la console.

Résultats

Notre fichier kernel.bin permettant de tester Claqu'OS via Qemu est disponible ici : Fichier:Claquos.tar.gz