Projet système PC : 2010 - Crombez Mathias,Hu Ningbo et Raïs Ramzi

De Ensiwiki
Aller à : navigation, rechercher
L'affichage à l'état initial


Présentation

Dans le cadre de notre cursus en deuxième année à l'Ensimag, nous avons choisi le projet système sur PC pour clore notre année. Ce projet a duré 4 semaines du 20 Mai au 16 Juin et cette page en représente une synthèse. Nous allons donc pouvoir s'arrêter sur nos choix et les difficultés que nous avons rencontré. Ce projet est avant tout une façon de nous faire apprendre, à nous étudiants, les mécanismes d'un système d'exploitation.

Le but du projet

Il s'agit donc de réaliser un système d'exploitation qui est le lien entre la machine et l'utilisateur. A partir de quelques sources fournis, nous avons réalisé d'abords le noyau, défini par la gestion des processus ( tâches du processeur ), l'ordonnancement ( classer l'exécution des processus ) et les entrées/sorties (la gestion du clavier, de l'écran et du temps ou horloge). L'utilisateur, par l'intermédiaire des applications ou "logiciels" (même si le système d'exploitation en est aussi un)), n'a pas accès directement au noyau, mais seulement par l'intermédiaire d'"appels système" qui sont les fonctions décrivant la librairie.

Notre équipe

Notre tuteur

Implémentation et Réalisation

L'énoncé du projet Système

Gestion de l'affiche à l'écran

Afin de pouvoir obtenir des messages d'erreur ou pour le débogage, il faut très rapidement faire l'affichage (déjà fait en pratique du système). L'affichage de messages simples est relativement facile, cependant c'est tout autre chose quand il nous faut approfondir car il faut gérer la couleur, les lignes et colonnes mais surtout la partie clavier qui est fortement lié.

Gestion des processus

Le processus est une tâche que l'on demande au processeur d'exécuter, il cache une fonction en C. Le processus est, en terme de code, une structure regroupant de nombreuses informations tels que le pid (son identifiant), la taille de sa pile, sa priorité ou encore son nom. Mais aussi des informations utiles pour le code, comme une copie de ses registres ( pour pouvoir récupérer l'exécution du processus sans perte d'information ), la liste de ces fils ou sa valeur de retour. L'un de ses éléments est l'état du processus :

État du processus

Description

ACTIF

Le processus est dans le processeur en fonctionnement.

ACTIVABLE

Le processus n'attend que son tour pour être ACTIF.

BLOQUE_FILE

Le processus est bloqué sur file vide (il doit recevoir un message) ou sur file pleine (il doit déposer un message).

BLOQUE_IO

En attente de l'appui d'un "entrée" au clavier.

BLOQUE_FILS

Le processus père est en attente de la fin de l'exécution d'un de ses fils (par un waitpid).

SLEEP

Le processus attend une date précise (par wait_clock), il sera réveiller par l'horloge.

ZOMBIE

Le processus fils est fini et son père ne l'attends pas, il ne fonctionne plus et n'attend que l'action de son père pour "mourir".

RDY_TO_DIE

Le processus fils était ZOMBIE, le père l'a attendu et le tue par l'intermédiaire de "kill".

BLOQUE_SHELL

Quand on utilise plusieurs terminales, tous les terminaux non actifs sont BLOQUE_SHELL pour éviter qu'ils récupèrent ce qui a été tapé au clavier.

On stocke les adresses des processus dans un tableau de 31 lignes pour 30 processus et le processus inactif (ou "idle" de pid 0) afin de pouvoir allouer des identifiants et pour pouvoir les localisé dans la mémoire.

Chaque processus connait son père par l'intermédiaire de l'identifiant et ses fils par l'intermédiaire d'une liste. Rappel : le fils d'un processus est un autre processus qui est créé dans le père.

Gestion de l'horloge

L'horloge est en fait une interruption, c'est-à-dire un signal envoyé au processeur, qui déclare qu'un certain nombre de "tic" du quartz a eu lieu. A chacune de ces interruptions, on affiche l'horloge avec une nouvelle valeur, on regarde si des processeurs peuvent être réveillé, et on appelle l'ordonnanceur.

L'ordonnancement

L'ordonnanceur est composé principalement d'une file qui prend en compte les priorités et le temps passé dans l'ordonnanceur. En effet, le prochain processus est sélectionné parmi les processus ayant la plus grande priorité.

Les files de messages

Les files de messages sont implémentés par une structure regroupant un tableau de messages ( qui fonctionne comme une file de type FIFO, First In First Out ) et une file de priorité pour les processus bloqués. Ce que nous appelons messages ici, est l'adresse sur le vrai message. En effet, pour les connaitre leur nombre, nous avons choisi de compter le nombre de cases non nulles dans le tableau. Il était aussi bien sûr possible de rajouter dans la structure, un compteur qui change pour chaque message, ou la prochaine case à remplir.

La console

A chaque fois qu'on appuie sur une touche, une interruption se déclare ( voir l'horloge ), on décrypte la touche sélectionné et on l'affiche en adaptant l'affichage selon la touche. Et quand on appuie sur "entrée", nous envoyons un message au premier processus qui est BLOQUE_IO pour que celui-ci l'interprète comme une commande. Voici les commandes qui fonctionnent :

help

Demande l'aide des commandes

ps

lit la table des processus

echo

test de la suppression de l'affichage des caractères tapés ( comme pour les mots de passes sur linux )

clear

Efface l'écran du terminal

Mode utilisateur/noyau

Il s'agit de la séparation entre la partie noyau, c'est-à-dire la gestion des processus, de l'horloge et du clavier, et la partie application (ou utilisateur), le terminal, l'exécution des processus. Cela se fait par des appels systèmes et des changements d'emplacements mémoires. Et tout d'abords par le changement de certains segments (ou description des propriétés) d'un processus.

Cette partie n'a pas été implémenté : nous avons remarqué seulement à la fin que cette partie avait été mal implémenté.

L'extension : Le multi-terminaux

Nous avons crée un ensemble de terminal comme linux qui sont en théorie indépendant l'un de l'autre. On utilisant l'état BLOQUE_SHELL, on bloque les processus qui gère les terminaux qui n'ont pas été affiché.

Un terminal et commandes

En terme d'affichage, c'est totalement indépendant, on passe entre terminaux avec F1 ... F5 (il y a un maximum de 5 terminaux).

Pour l'exécution des processus et de l'affichage en arrière plan, cela n'a pas été implémenté.




Gestion de projet

Gestion de l'équipe

La principale difficulté de cette partie est la séparation des tâches selon les capacités de chacun. Mais surtout, il y a le contrecoup de la spécialisation, car il existe toujours des thèmes du projet que certains connaissent parfaitement pour l'avoir implémenté alors que d'autres ne connaissent que les bases : le retour d'expérience est inéquitable dans l'équipe .

Gestion du temps

Le projet est particulièrement long et fastidieux, non pas en terme de lignes de code mais en terme de compréhension. En effet, comme dit plus haut, il s'agit d'un projet qui sert principalement à nous faire connaitre le fonctionnement d'un système d'exploitation et cela prend du temps. De plus, même si le projet est divisé en phase, elles sont inégales en terme de difficultés et de temps passé.

Répartition des tâches

Mathias Crombez
  • Fonctions primaires du processus
  • Files de messages
  • Filiation des processus
  • Horloge et timer
  • Multi-terminaux
Ningbo Hu
  • Clavier
  • Affichage
  • Console
  • Gestion projet
Ramzi Raïs
  • Partie assembleur
  • Changement de processus
  • Ordonnancement
  • Changement de mode : gestion du mode utilisateur et appels systèmes


Les Difficultés

Gestion des processus

Ce fut la première partie et l'une des partie les plus difficiles car nous devons comprendre le sujet et savoir par ou commencer. La partie la plus difficile fut le changement de contexte qui nous a pris un peu moins d'une semaine (en parallèle des primitives des processus). Nous pensions tout d'abords faire un code en C en incluant de l'assembleur mais cette réponse ne convenait pas car il fallait être rapide et efficace (car il s'agissait d'un facteur pouvoir grandement atteindre l'efficacité du noyau puisque très courant). Nous sommes donc passé dans un programme écrit entièrement en Assembleur. De plus, savoir ce qu'il fallait faire exactement, et la syntaxe de ce langage (Assembleur AT&T utilisé par le compilateur GCC) étaient difficiles.

L'ordonnancement

Dans une moindre mesure, cette partie était difficile car elle demandait de maitriser les "queues", files de priorité fournis, qui différent de tout ce que nous avons appris dans ce domaine.

La terminaison des processus

Même si l'idée de départ de ce que nous avons de la terminaison des processus était proche de la réalité. Il a fallut de nombreux tests parmi ceux fournis par les enseignants pour les perfectionnés. En effet, il fallait prendre en compte les nombreux cas possibles et les suppressions des nombreux liens avec d'autres structures (files de messages, filiation ...). Cependant, on peut rajouter un problème qui perdure dans la version "finale" du code : les fuites de mémoires. En effet, certaines zones ne sont pas bien libérés comme la pile utilisateur (problème d'allocation ou autres ...) ou certains emplacements alloués dans les files, listes et autres ... On remarque cette erreur en lançant tous les tests (qui sont validés) fournis, on arrive à une erreur d'allocation (représentée par un identifiant ou pid inférieur à 0).

Le passage entre le mode user et le mode kernel

Nous le pensions fini jusqu'à ce que nous voyons que les paramètres décrivant le mode utilisateur étaient faux. Nous nous sommes aperçu de l'erreur trop tard pour pouvoir changer quelque chose malgré nos efforts. Le code fournis a donc bien une séparation physique pour la mémoire allouée et les appels systèmes (mais ils restent en mode user), mais en pratique nous ne pouvons dire que nous travaillons en mode user.

Le shell

Certaines fonctions décrites dans le help n'ont pas été implémentées correctement, il suffit d'une petite modification pour les faire fonctionner mais nous l'avons vu trop tard pour le faire. La fonction clear comporte une petite erreur : elle efface aussi la banière et ne remet pas le curseur en position initiale.


Résultats

Nous avons donc un système d'exploitation fonctionnant uniquement en mode kernel. Cependant, les tests fournis nous ont permis de débuggé notre programme. Sur les 20 tests, seul deux nous résitent : les tests vérifiant les modifications de registres lors d'un changement de processus et le tests permettant de "hacker" notre système (étant en mode kernel, il s'exécute tout simplement pas). Cependant les files de messages, la gestion de processus, l'horloge, l'ordonnancement et les terminaux marchent sans erreur notable (outre celles définies ci-dessus).


Conclusion

Le principal but est en grande partie atteint, nous faire apprendre les rudiments de la constitution et de la programmation d'un système d'exploitation. Sur ce point, toute l'équipe est d'accords. Cependant, l'erreur du changement de mode nous a particulièrement frustré sur la fin. Même si notre projet n'est pas, selon nous, réellement fini, nous avons obtenu la satisfaction d'avoir appliqué nos connaissances théoriques en équipe sur un projet de cette envergure.

Documentation

Nous pouvons ajouter que notre code ne comporte aucune source externe, hormis le code provenant du TP de pratique de système de Ramzi Raïs et les sources et tests des enseignants. Cependant, il y a une certaine inspiration (plutôt rare) provenant de l'Embedded GNU C Library (EGLIBC) version 2.11.1 du projet GNU et du noyau Linux version 1.0.

Outils utilisés