Projet système PC : 2017 - Lounès Saadi, Andy Pagès, Julien De Wisscher

De Ensiwiki
Aller à : navigation, rechercher
Logan
LoganHome.png
Projet Système d'Exploitation 2017

Développeurs Lounès Saadi Andy Pagès Julien De Wisscher

Gestion de projet

La gestion de projet a été une étape importante de ce projet. Afin de ne pas prendre de retard sur le rendu final, il a fallu s'organiser efficacement. Pour cela, dès le début du projet, nous avons découpé tout le projet en sous-tâches afin d'avoir du projet dans sa globalité. Avec ces sous-tâches, un planning prévisionnel a été mis en place ainsi qu'un trello.

Planning prévisionnel

Pour définir une prévision de notre emploi du temps, nous avons décidé d'opter pour un diagramme de Gantt. En suivant ce diagramme, le projet se finirait à temps et avec toutes les fonctionnalités demandées.

GanttPrevisionnel.png

Notre roadmap

Roadmap1.png

Roadmap2.png

Déroulement effectif du projet

Il est important de noter que, bien que notre projet ait terminé dans les temps (un jour en avance) avec toutes les fonctionnalités demandées et plus encore, son déroulement a été bien différent de ce que l'on avait pu prévoir. En effet, nous avons passé une grande partie du projet sur les phases 3 et 4. Nous avons même pensé que cela nous mettrait en retard. En revanche, nous avons passé très peu de temps sur la phase 5 contrairement à ce que nous avions pu imaginer au début du projet.

Afin de garder une équipe au courant du déroulement du projet, nous avons mis en place des réunions quotidiennes pour parler de l'avancement du projet, des difficultés rencontrées, des choses à améliorer...etc.

GanttEffectif.png

Journal de bord quotidien

Nous utiliserons cette page wiki tout au long du développement de ce projet pour maintenir notre journal de bord. Au terme de ce projet, nous mettrons en forme ce journal afin qu'il soit plus propre et lisible.

08/06/2017

  • Lecture et analyse du sujet
  • Réflection sur les méthodes de gestion de projet que nous allons adopter.
  • Installation de l'environnement sur machines personnelles (Mac OS)
  • Mise en place des outils qui vont garantir le bon fonctionnement du projet (trello, git, CI, test)
  • Début d'implémentation de l'affichage écran

09/06/2017

  • Point sur la phase 1 réalisée la veille
  • Debut de la phase 2 en pair programming et début des tests
  • Difficultés à comprendre ce que l’on doit faire exactement sur les processus
  • Difficultés technique liées au langage C
  • Phase 2 quasiment terminée -> il reste un bug sur les interruptions

12/06/2017

  • Débuggage phase 2 -> interruption -> terminaison phase 2
  • Rédaction du planning de la semaine
  • Planning à long terme
  • Refactoring du code déjà présent
  • Utilisation de la fifo pour la table des processus

13/06/2017

  • Processus sous forme de liste FIFO
  • Regression rencontrée

14/06/2017

  • Débuggage des bugs de la veille
  • Terminaison des processus (exit, return, kill)
  • Commencement de waitpid

15/06/2017

  • waipid terminée
  • Début de la phase des tests

16/06/2017

  • Début de la phase d'endormissement
  • Début de la phase 4

19/06/2017

  • Débuggage des tests
  • On arrive au test 13 (inclu)

20/06/2017

  • On continue à faire passer les tests
  • On commence phase 5

Journal de bord quotidien

Phase 1

Cette phase consistait à prendre en main l'environnement de travail et gérer les affichages basiques à l'écran. Elle a été très rapide étant donné que nous avions déjà quasiment tout implémenté l'an dernier lors du cours de Logiciel de base.

Deux des membres de l'équipe travaillant sur MacOS, nous avons pris le temps de bien configurer notre environnement et de modifier les Makefile en conséquence pour pouvoir effectuer l'intégralité du projet sur nos machines personnelles.

100 %

Phase 2

La deuxième phase était elle aussi dans le prolongement du cours de l'an passé. Il a fallu gérer le timer et les interruptions associées (choses que nous avions déjà implementées). Cette partie a donc été très rapide. Concernant le context_switch, les informations disponibles sur ensiwiki nous ont permis de le mettre en place très rapidement.

100 %

Phase 3

Phase centrale du projet, nous avons décidé d'être pointilleux sur cette dernière, de bien réfléchir et tout tester pour éviter d'avoir à revenir dessus par la suite. Le travail a été majoritairement effectué en deux sous-groupes, un binôme de développement, et une personne centrée sur les tests. Cette méthode s'est montrée être très pertinente, car nous n'avons eu que peu de changements à faire par la suite.

Concernant nos choix, nous avons décidé d'utiliser en grande partie les queues disponibles dans le squelette du projet, plutôt que d'utiliser des tableaux. Cela nous a permis d'énormément gagner en lisibilité de code.

Ainsi, la terminaison, waitpid et le scheduling se sont representés sous la forme d'ajouts/suppressions dans différentes listes, correspondant aux états des processus (READY, RUNNING, WAITING_SON, ZOMBIE, etc..). Le scheduler avait donc seulement à choisir le bon processus READY, ce qui était extrêmement simple grâce aux queues fournies (unique appel).

Problème rencontré : nous n'utilisions pas la même librairie d'allocation et de libération de la mémoire (mem_alloc, puis kfree). Le code fonctionnait jusqu'aux tests de fin de phase 4, mais nous avons rencontré des soucis de performances et d'explosion de piles sur les créations/destructions en chaîne. Il faut donc bien utiliser les appels des mêmes libraires (kmalloc/kfree ou mem_alloc/mem_free).

100 %

Phase 4

Cette phase s'est découpée en deux parties bien distinctes : les files de messages et les tests fournis dans le squelette (18/19 non inclus).

Les files de messages basées sur le modèle producteur/consommateur n'ont pas été sources de problème de conception. Une seule personne a donc été chargée de développer cette fonctionnalité. Pour ce faire, de nouveau, les queues ont été utilisées.

Nous avions déjà écrit une méthode sleep() à la phase 3, le wait_clock() a donc été très rapide, étant très similaire (attente en seconde / attente d'un certain nombre de tics).

Le binôme s'est consacré aux tests et aux corrections à apporter au code existant pour valider l'intégralité des tests avant de passer à la phase 5.

Il est primordial de bien faire passer tous les tests à cette étape avant de passer à la phase 5, où il est plus compliqué (mais loin d'être impossible!) de débugger les tests.

100 %

Phase 5

Après avoir terminé les tests de la phase 4, nous nous sommes penchés sur la partie user.

Initialement, un binôme devait se consacrer à la phase 5 pendant qu'une personne se chargeait de la phase 6. Malheureusement, après avoir entamé la phase 5, nous avons découvert un faux positif dans nos tests (cf phase 3, allocation/libération), et un membre du binôme s'est consacré à la résolution des bugs. Le second, relativement à l'aise avec les concepts de la phase 5 a pu continuer seul (plutôt que de débaucher la personne sur la phase 6 qui était lancée).

La phase s'est découpée en 3 parties, que nous avons fait dans cet ordre :

  • Appels systèmes : nous avons d'abord implémenté un squelette d'appel système dans shared, sans traiter les interruptions. (binôme)
  • Switch user mode : simulation d'une interruption 49 et iret pour changer de segment.
  • Appels systèmes avec interruptions et séparation des piles kernel/user

S'en est suivi une phase de tests côté user (les mêmes qu'avant, mais côté user). Nous n'avons eu quasiment aucun problème ici, probablement grâce au temps pris pour valider nos choix et nos tests aux phases 3/4.

Astuces :

  • Analysez bien, avec les ressources disponibles sur le wiki comment sont construites les piles user et kernel. L'implémentation du jump_usermode ne nécessite que très peu de lignes de code. Le C permet de construire les piles kernel et user (user_stack_alloc pour user !), et l'assembleur n'a servi qu'à sauvegarder des registres importants et faire l'iret (6 lignes).
  • Pensez à allouer de la mémoire pour la pile user, même si ssize vaut 0 ! En effet, un appel système essaiera forcément d'empiler des choses.. ce qui risque d'être compliqué si aucune case mémoire n'a été allouée !
  • Utilisation de GDB : il est parfois compliqué de débugger l'assembleur, mais gdb permet d'éxecuter l'assembleur ligne par ligne. Utilisez les commandes la asm (passage en mode assembleur) puis si pour avancer ligne à ligne. Parfois il arrive que l'affichage plante totalement, tapez alors reset puis recommencez.
100 %

Phase 6

Afin de pouvoir tester la phase 5 et d'afficher des choses dans la console utilisateur, il a été décidé de commencer la phase 5 en parallèle de la phase 6. Ainsi, il était très simple d'écrire la primitive cons_write afin de pouvoir utiliser printf côté user. Pendant cette phase, nous avons profiter pour faire la mise page de la console afin d'avoir un rendu comme ci-dessous :

Logan.png

A tout moment lors de l'utilisation de notre système d'exploitation, l'utilisateur a accès à la date, l'heure et la durée de son exécution.

La phase 6 s'est complexifié au moment où il a fallu implémenter la primitive cons_read. En effet, la difficulté est légèrement supérieur à celle de cons_write. Pour cela, nous avons utiliser les queues pour mettre en attentes les processus lors de l'appel de cons_read jusqu'à qu'un retour chariot soit entré. La gestion du buffer a été compliqué notamment avec les améliorations console que l'on a apporté : déplacement dans une ligne avec les flèches, backspace, historique.

100 %

Phase 7

Pour implémenter le shell, nous avons opté pour une comparaison de chaînes de caractères au lieu d'un parser étant donné le peu de commandes initiales possibles. Nous avons implémentées les commandes ps, exit et echo comme demandées.

Nous avons rajouté quelques fonctionnalités telles que la gestion des flèches LEFT/RIGHT qui permettent de déplacer le curseur, mais aussi les flèches UP/DOWN qui permettent d'accéder à l'historique des cinq (nombre arbitraire) dernières commandes tapées. Nous avons aussi rajouté le clear, ainsi que l'appel aux tests (run_tests). . En plus, notre shell affiche l'heure et la date, et permet de lancer un jeu quizz avec la commande run_quiz.

Tous ces appels utilisent des primitives systèmes, pour bien séparer la partie kernel et user.

100 %

Extensions implémentées

  • Sémaphores
  • Commandes supplémentaires sur le shell : date, petit jeu, gestion de l'historique des commandes, clear.

Piste d'évolution

Ce projet n'est bien sûr pas parfait. Il reste des choses à améliorer. L'interprète de commandes pourrait être amélioré afin de pouvoir saisir des commandes avec arguments. Il serait également intéressant de mettre en place un système de gestion de fichiers afin de rendre le système d'exploitation complet.

Notre point de vue sur le projet

Ce projet nous a permis de comprendre, de manière pratique, comment un système d'exploitations fonctionne. Aussi, bien que ce soit peu quantifiable, nous pensons avoir aussi progressé en C.

Quant à l'organisation, il est parfois difficile voire impossible de partager les tâches.