Projet système PC : 2016 - Rémy Beulé Dauzat, Vincent Chenal, Jeremia Oberle

De Ensiwiki
Aller à : navigation, rechercher
Flaming'OS
Logo flamingos.png
Projet Système 2016

Développeurs BEULE DAUZAT Rémy
VINCENT Chenal
OBERLE Jeremia

I Présentation

Bienvenue sur la page de présentation de notre système d'exploitation : Flaming'OS (flamants roses). Il s'agit du projet de fin de deuxième année pour les alternants. Cette page résume l'ensemble des fonctionnalités implémentées aux diverses phases du projet ainsi que les outils utilisés.

Équipe

BEULE DAUZAT Rémy
CHENAL Vincent
OBERLE JEREMIA

Fonctionnalités

Notre système d'exploitation implémente les fonctionnalités décrites dans le cahier des charges ci-dessous.

II Cahier des charges

Le projet est découpé en 7 phases :

  • Phase 1 : Affichage de caractères à l'écran
  • Phase 2 : Création de processus et changement de contexte entre 2 processus
  • Phase 3 : Création dynamique de processus, filiation entre processus et terminaison de processus
  • Phase 4 : Communication entre processus et attente
  • Phase 5 : Séparation de l'espace mémoire entre noyau et utilisateur; séparation du mode utilisateur
  • Phase 6 : Gestion du clavier
  • Phase 7 : Gestion du shell
  • Extensions


III Planning

voici le planning prévisionnel que nous avions réalisé en début de projet :
Gant previsionnel.png

voici le planning effectif tiré du carnet de bord :
Gant effectif rbd.png

IV Réalisation

Phase 1

Prise en main du code fourni, de l'environnement de développement et gestion de l'affichage à l'écran

Cette première phase nous a permis, en nous basant sur le mini projet de logiciel de base de l'année dernière, d'appréhender le code fourni et de proposer un moyen d'afficher du texte à l'écran (via printf notamment). Concrètement nous avons :

  1. Récupéré le TP de logiciel de base.
  2. Adapté la partie affichage au nouveau projet.
  3. Corrigé le défilement de l'écran.
  4. Ajouté l'affichage de la clock (nombre de secondes depuis le démarrage).


Implémentation :

100 %

Phase 2

Introduction des concepts clés : processus, changements de contexte, partage du temps, ...

Nous avons tout d'abord commencé par mettre en place les structures nécessaires à la gestion des processus : structure 'Process' contenant toutes les informations utiles, primitives de création/modification des processus, tableau de processus, processus courant, etc.
Nous nous sommes ensuite penchés sur la problématique de changement de contexte entre deux processus : d'abord en appelant explicitement la fonction 'context-switch' puis dans un deuxième temps en déclenchant celle-ci via une interruption matérielle.

Nous avons profité de la fin de cette phase pour :

  • Refactoriser le code lié aux processus
  • Corriger la fréquence de l'horloge matérielle


Implémentation :

100 %

Phase 3

Gestion du cycle de vie des processus

Cette phase était dédiée à la gestion du cycle de vie des processus, c'est à dire la façon dont il sont ordonnancés, endormis, tués lorsqu'ils ont terminés leur travail. L'ordonnancement des processus en tenant compte de la priorité de ceux-ci est grandement simplifié par la bibliothèque "fifo" fournie qui permet de retirer de la liste l'élément le plus prioritaire : notre prochain élu. Cette étape fut relativement facile à implanter du fait qu'il est encore assez facile de débugger le code lorsque l'on est encore en mode noyau. On peut donc mettre un point d'arrêt dans la fonction d'ordonnancement et suivre facilement, tour après tour, qui est le prochain élu.

La deuxième partie de cette phase fut la mise en place de la terminaison des processus. Auparavant nous n'utilisions que des fonctions qui ne se terminent jamais. Cette étape nous a prise du temps, notamment pour mettre en place les primitives kill et waitpid qui nécessitent de bien avoir compris les spécifications (fils zombies, libération de la mémoire au bon moment/endroit).

Nous avons fini cette phase en validant les tests fournis.

Implémentation :

100 %

Phase 4

Mise en place des files de messages ainsi que de l'endormissement programme des processus

Cette phase était dédiée à deux fonctionnalités importantes du système : les files de messages qui permettent la communication entre processus, et les primitives liées à l'horloge qui permettent notamment de programmer l'endormissement d'un processus pour une durée fixée.

Pour les files de messages nous avons créé une structure Message_queue qui correspond à une file. La structure contient deux attributs importants: une fifo de processus bloqués sur la file et un tableau qui stocke les messages. Nous avons utilisé la fifo fournie pour les processus bloqués et pour le tableau nous avons implémenté un tableau fifo à deux indexes. Le tableau est alloué à la création de la file. Nous avons préféré de gérer un tableau à deux indexes plutôt que d'utiliser la fifo fournie pour les messages. Le tableau nous permet d'allouer la taille nécessaire pour les messages à la création de la file. Avec la fifo triée nous aurions eu besoin d'allouer de la mémoire pour un message à chaque psend et de la libérer à chaque preceive. Nous pensons qu'un tableau est plus efficace et performant.

Nous avons mal compris la spécification de preceive et de psend ce qui fait que nous avons ajouté au fur et à mesure plus de conditions dans ces méthodes. Si nous recommencions du début maintenant il y aurait moins de code et les méthodes seraient plus lisibles. Le point principal que nous avons traité différemment est le psend sur file pleine. Si un processus fait un psend sur une pile pleine il se bloque. Si alors un autre processus fait un preceive c'est à lui de prendre le message du psend et de le mettre dans la file. Ce n'est pas le processus qui a fait appel à psend. Le test 13 teste ce comportement.

Implémentation :

100 %

Phase 5

Ce fut clairement la phase la plus difficile pour toutes les équipes. Nous avons travaillé pendant presque toute une semaine sur cette partie. Le plus compliqué fut de savoir par où commencer et maîtriser les outils de débogage. En effet, nous n'avons pas trouvé de solution efficace pour obtenir le code à la fois de la partie user et à la fois de la partie kernel. Nous avons donc passé énormément de temps à déboguer presque à l'aveugle ce qui fut très compliqué.

Nous avons commencés par implémenter la liste des appels systèmes et le traitant nécessaire car c'est ce que l'on comprenais le mieux. Nous avons ensuite créé les deux piles (User et Kernel). Mais la partie la plus importante fut de démarrer un processus en mode user. Ce fut très intéressant car il y a très peu de code mais beaucoup de réflexion avant de l'écrire. Cela nous a permis de mieux comprendre l'ensemble du fonctionnement de notre os, des piles, etc. Nous avons beaucoup utilisé le tableau et des feuilles de papiers pour mieux comprendre les différents mécanismes en jeu.

Ce point délicat se décompose en plusieurs étapes dans notre système :

  • dans le start, nous initialisons la pile kernel du futur processus avec les valeurs eip, cs, eflags, esp, ss.
  • toujours dans le start, nous initialisons la pile user avec l'adresse du wrapper coté user qui permet d'exit correctement et avec les arguments.
  • pour terminer dans le start, la valeur d'esp enregistré dans la structure du processus, pointe vers un petit programme en assembleur qui nous permet de booter en mode user
  • ensuite, le scheduler est appelé. Il arrive au contexte switch qui va donc avec son ret aller dans notre fonction de boot
  • cette fonction de boot met en place les segments de registres pour le mode user et fait un iret qui dépile toutes les valeurs enregistrées au début dans la pile kernel

Nous sommes maintenant en mode user. Cela parait presque simple maintenant mais nous vous assurons que c'est la partie qui à nos yeux est la plus compliquée du projet et qui nous a pris le plus de temps.


Au niveau des appels systèmes, nous avons constitué une librairie de fonctions qui font toutes des appels systèmes à l'aide de l'interruption 49 et en passant les paramètres dans les registres. Du coté kernel, un switch fait les appels aux bonnes fonctions par rapport au numéro d'appel enregistré dans eax.

Implémentation :

100 %

Phase 6

Le clavier a un buffer de taille fixe et une fifo. La méthode keyboard_data remplit le buffer avec ce qu'il lit du clavier. Si l'utilisateur tappe Enter le buffer est ajouté à la fifo et vidé. Pour la fifo nous avons utilisé les files de messages. Chaque caractère est un message. Avoir utilisé les files de messages avait pour l'avantage que l'endormissement et le réveil étaient déjà gérés. Nous gérons aussi les touches des flèches. Il y a deux cons_read différents. Il y a cons_read et cons_read_with_history. La première renvoie tous les caractères lu (inclus les flèches). La deuxième gère l'historique du shell. En cas de flèche haute le buffer est mis à jour avec la dernière commande tapée et elle est affichée.

Implémentation :

100 %

Phase 7

Cette étape fut relativement rapide à réaliser : 1 journée car elle consiste a créer une interface de commande très simplifiée. Ajouter des commandes aux shell fut assez facile car nous avions déjà toutes les étapes précédentes qui fonctionnaient. Nous avons créé les commandes ps / help / kill / echo / test (permet de lancer les tests des professeurs). Chaque processus n'est lancé qu'avec une taille de 4096 octect comme pile utilisateur. C'est une valeur par défaut que nous avons utilisée.

Implémentation :

90 %

Cette partie ne peut jamais être totalement terminée en réalité car il est toujours possible d'ajouter des commandes

Phase d'extension

La phase d'extension est dédiée à l'ajout de fonctionnalités dans le shell. Ces fonctionnalités sont accessibles via des commandes tapées par l'utilisateur das le shell. Nous avons commencé par ajouter les fonctionnalités ps, cons_echo, clear , test et help. Puis ensuite nous avons réfléchi à ce que l'on avait envie d'ajouter.
Nous avons donc ajouté :

  • la gestion des fuseaux horaire : settimezone +/-[nb]
  • la gestion d'un historique des commandes (1 seul niveau) : history
  • la terminaison d'un processus par pid : kill pid
  • l'affichage du logo de l'OS : flamingos
  • la possibilité de changer la couleur du texte et du fond : ch_font_col num, ch_back_col num
  • une simulation "jeu de la vie" : gof
  • un jeu de type space invaders : invader

Bilan

Ce projet nous a permis d'approfondir nos connaissances en systèmes d'exploitations et de pratiquer les langages c et assembleurs. Ce qui est intéressant c'est qu'il y a surtout de la réflexion et pas énormément de lignes de codes à coder. Cela permet d'adapter le travail à de nombreux profils : les gens aimant le c, le bas niveaux, l'assembleur, l'algorithmie ...

Le fait d'avoir les tests des professeurs ne dispense pas d'en effectuer par soit même, surtout au début, mais cela permet de se concentrer essentiellement sur la logique. On perd ainsi moins de temps à écrire des dizaines de tests pas toujours très efficaces.

voici le fichier de notre os :

Liens externes

le logo : http://drawingstutorial.com/how-to-draw-a-flamingo/
random : https://www.quora.com/How-do-you-create-your-own-randomize-function-in-C