[Kos-announce] Nouveautes de la semaine
d2
David.Decotigny@irisa.fr
06 Aug 2001 12:05:59 +0200
Bonjour,
Durant la semaine passee, Julien, Thomas et moi nous sommes reunis
chez Thomas pour faire avancer KOS. Au programme : codage,
uniformisation, blindage du coeur de l'OS et brainstorming (Babel et
VMM).
Grand Merci a lui et a ses parents pour l'agreable sejour que nous
avons pu passer ensemble a (entre autre) coder KOS et a ecouter du
Mozart. Ca a ete une semaine productive, tant sur le plan des
realisations, que sur le plan du design du coeur de l'OS. Des docs
(Babel + gestion des interruptions) devraient suivre.
Quand on essaye KOS tel quel (recup source + compilation ou image
disquette), on ne remarque pas de nouveaute neuve nouvelle a
l'ecran. Mais il faut savoir que le test effectué en arriere plan
(invisible a l'ecran sauf quand une erreur se produit) est assez
violent :
- 20 threads cpl0 qui font 2000 campagnes d'allocation/deallocation
aleatoires de 1234 elements de taille aleatoire comprise entre 4
et 2048 octets chacune, avec usleep() aleatoire entre chaque
campagne. Permet de tester intensivement la gestion de la memoire
noyau, et la synchronisation.
- 1 paire de threads cpl0 producteur/consommateur utilisant les
primitives de kmsg. Le producteur est lance toutes les secondes.
- 1 DSR "marqué" a chaque interruption clavier
- 1 paire de DST bloquants associes au timer, synchronises par kmsg
- 2 threads cpl0 de twidlle (les 2 caracteres rouges a l'ecran)
- 2 threads qui ne font rien (terminent immediatement)
- 1000 interruptions timer par seconde (HZ=1000) + twiddle (caractere
bleu en haut a droite)
Pour les termes obscurs (DST, DSR, kmsg, ...), voir ce qui suit.
Si vous voulez tester, 40M de RAM minimum sont recommandes. Sinon vous
aurez droit a un :
[get_physical_page_unsafe@_pmm.c:71] **** System Halted **** :
No more physical memory
Vers le debut.
Bochs n'est pas le meilleur choix pour tester : tres lent, et vous
aurez l'impression que les ticks d'horloge deviennent de plus en plus
lents. Utilisez un ordinateur reel avec debug sur ligne serie, c'est
plus rapide et moins "surprenant".
Thomas a redige le compte-rendu plus detaille ci-dessous.
Compte rendu semaine KOS
------------------------
Une semaine de développement KOS s'est déroulée du vendredi 27 juillet
au 5 aout, avec Julien, David et moi-même. Jérome et Estelle sont
venus voir l'avancée du développement et nous apporter leurs
suggestions le dernier jour.
Travaux réalisés
----------------
1 - Scheduler : reorganisation (toujours du round-robin)
Découpage du module scheduler en plusieurs fichiers, en respectant
les usages dans le nommage des fichiers. Trois parties composent ce
scheduler : _timer.c qui contient le handler de l'IRQ timer,
_scheduler.c qui s'occupe d'élire un nouveau thread (fonction
reschedule_unsafe), et de relancer un nouveau thread (fonction
rechedule_next). Une fonction reschedule_after_interrupt est aussi
présente, et elle est appelée après chaque IRQ (voir plus loin). Le
fichier _sleep.c contient les primitives nécessaires à la gestion de
la fonction usleep().
2 - task-x86 : problemes de synchro
Découpage du module task-x86 en plusieurs fichiers. La partie
gestion des TSS qui faisait auparavant partie de mm-x86 est
maintenant dans task-x86 (fichier _tss.c). Modification des
cpl0_switch_context pour qu'ils ne fassent pas le 'sti' brute force
(trop bourrin avec les spinlocks).
3 - IDT : DSR et DST
Réécriture quasi complète de la gestion de l'IDT. Les "prehandlers"
se trouvent dans _idt.S, la gestion du (ou des syscalls) est dans
_syscall.c (le syscall existe mais ne fait presque rien). La gestion
des irq dans _irq.c, la gestion des exceptions dans
_exception.c. D'autre part la partie spécifique au i8259 a été
placée dans un fichier a part (_i8259.c). Grande nouveauté : les DSR
et DST.
DSR : Deferred Service Routine, plus ou moins équivalents aux
tasklets de Linux (noyau 2.4) ou aux bottom half (noyau
2.2). Les DSR sont des fonctions qui sont éxécutées après le
traitement de la dernière IRQ la plus externe (lors de
l'éventuelle imbrication d'IRQ), et ce avec les interruptions
activées. Nous avons actuellement 42 niveaux de DSR, avec pour
le moment une fonction par niveau. La fonction de niveau 0
étant éxécutée avant la fonction de niveau 1. Ces fonctions
sont éxécutées avec les interruptions activées sur le
processeur courant. Deux DSRs différents peuvent s'éxécuter
simultanément sur plusieurs processeurs, de même que le même
DSR peut s'éxécuter simultanément sur plusieurs processeurs.
DST : Deferred Service Thread, plus ou moins équivalents aux
softirqs de Linux 2.4.7+. Lorsque le traitement à faire après
une interruption peut etre bloquant (attente sur ressource),
il convient d'utiliser un DST plutôt qu'un DSR, car
l'utilisation d'un DSR pénaliserait le thread qui aurait reçu
l'IRQ pour un temps assez long (attente sur ressource). Les
DST sont donc des threads, actuellement au nombre de 16 (16
niveaux). Chaque thread peut éxécuter un nombre illimité de
'jobs'. Deux jobs d'un niveau différent peuvent s'éxécuter en
même temps sur des processeurs différent, mais deux jobs d'un
même niveau ne peuvent s'éxécuter en même temps sur des
processeurs différent.
Nous allons prochainement écrire une documentation expliquant
précisement l'implémentation de la gestion des interruptions.
4 - KITC : ksignal et kmsg
Un nouveau module kitc a fait son apparition : Kernel Inter Thread
Communication. Il contient des primitives de communication inter
thread RESERVEES au noyau. Ces primitives sont donc simples, mais
aussi rapides. On a _ksignal.c qui implémente des fonctions
permettant à un thread de bloquer tant qu'un autre thread n'envoie
pas un signal. _kmsg.c implémente une gestion de boites aux lettres
(ports) de base, reposant sur ksignal.
5 - Module kos : headers globaux dans <kos/*.h>
Création d'un module kos, contenant wolfgang.c (partie principale du
noyau), et tous les .h qui étaient en bazar dans modules/. Le module
wolfgang a donc été supprimé.
6 - Module bootstrap : init levels + suppression de l'identity mapping
Un nouveau module bootstrap qui se charge de supprimer l'identity
mapping qui n'est plus nécessaire, puis d'initialiser les
modules. Ce n'est donc plus kos_main dans kos/wolfgang.c qui est le
point d'entrée du noyau pour le loader, mais la fonction
kernel_bootstrap dans le module bootstrap. D'autre part,
l'initialisation des modules a été repensée : on peut avoir
plusieurs init_module par module : il y a des 'init levels'. Tous
les init_modules de level 0 sont éxécutés, puis tous les
init_modules de level1, puis tous les init_modules de level3 ... Ceci
permet de supprimer certaines contraintes que nous avions concernant
l'ordre d'initialisation des modules. Les levels sont définis dans
loader/mod.h
7 - kmem : Tout repose sur kslab
Réécriture du module kmem (non terminé, il manque
kslab_cache_destroy). L'utilisation de slab est toujours à l'ordre
du jour, mais la nouvelle implémentation se rapproche de celle
proposée par Bonwick, et utilisée dans SunOS. On utilise des listes
chainées de blocs libres (sans avoir a les parcourir) plutot que des
bitmaps, ce qui est finalement plus simple et nettement plus
rapide. De plus, on peut maintenant avoir de cache avec des blocs de
grande taille, car les slabs peuvent faire plusieurs pages. Ce
module a été testé via _kmem_test.c.
8 - liblist
Finition de liblist. Cette librairie (un .h) est un ensemble de
macros pour gérer simplement des listes chainées. Très pratique,
nous l'utilisons au maximum dans le système. Toutefois, nous
envisageons sous peu de passer à des listes circulaires.
9 - loader : bootmem + exportation de variables + modules 'ar'
Relecture et correction de bugs mineurs dans bootmem (allocateur de
mémoire du loader). Possibilité d'exporter des variables entre les
modules. Toutefois ceci ne doit être utilisé que dans les cas
extremes (ex : spinlock). Correction de bugs sur l'ordre
d'initialisation des modules qui étaient inversés lors du
désarchivage d'une archive ar. Tous les modules sont maintenant
regroupées dans une archive ar, gzippée ou non. C'est plus rapide à
charger avec Grub.
10 - Synchronisation : blindage + anticipation SMP
Grosses reprises de code concernant la synchro : nous avons revu
tous les spinlocks dans tous les modules, pour corriger de nombreux
problemes de synchro. Nous avons tenu compte du multi processing
(même si celui ci n'est pas encore implémenté dans KOS). Ces
reprises concernent notamment le module idt, scheduler, kitc mais
aussi les modules de gestion de la mémoire (pmm, kmem). Les
deadlocks canoniques (appeles 2 fois de suite un lock sans unlock
intermediaire) sont detectables (macro __DEADLOCK_CHECK__ du config.h).
11 - Babel
Ce collecteur d'interfaces et d'instances avance bien. Le module
babel contient un fichier babel.h donnant les structures de base de
tout objet Babel. La sous partie tower est le collecteur
d'interfaces en lui meme. La sous partie syscall s'occupera plus
spécifiquement de recevoir et de gérer les syscalls. La sous partie
resource est destinée à définir ce qu'est la resource de base.
Pour résumer brièvement, Babel permet d'enregistrer des interfaces,
et d'instancier ces interfaces. Ainsi, on peut enregistrer
l'interface disk_ide, et créeer deux instances ide_disk_0 et
ide_disk_1 correspondants à l'interface. On appelle aussi ces
interfaces des services, et elle peuvent être organisée en classes
de services. Par exemple la classe de service disk définira des
méthodes telles que read,write,format,etc... mais ne sera pas
instatiable. Seul un service tel que disk_ide héritant de la classe
de service disk et proposant au minimum les méthodes de la classe de
service disk et éventuellement d'autres pourra être instancié. Les
classes de services correspondent en quelque sorte à des classes
abstraites, les services à des classes, et les instances à des
objets.
D'autre part, nous avons introduit la notion de ressource. Une
ressource est propre a chaque team. Elle peut représenter n'importe
quoi : un fichier, une socket, une carte son, un disque dur, un port
d'IPC, etc... Chaque ressource est liée à un instance de service,
via un lien appelé translator. Ces ressources sont créés lors d'un
open, et peuvent donc être comparées aux file descriptors sous
Unix. Toutefois la ressource n'est pas vue comme un fichier, mais
plutôt comme un objet sur lequel on peut appliquer les méthodes du
service lié par le translator.
Cette nouvelle notion de ressource, dont nous avions déjà discuté
sur la mailing list kos-dev nous a permis de bien comprendre comment
allait fonctionner globalement le système, de l'appel open() du
programme utilisateur à l'éxécution du bon open du bon service dans
le noyau.
12 - Brainstorming VMM
Gestion de la mémoire virtuelle. Sur ce point ci, nous avons
progressé durant cette semaine. Nous allons implémenter un système
assez classique, ala SVR4.
Dans KOS, les régions virtuelles contiendront :
- un pointeur vers une shadow ressource représentant la
ressource mappée en mémoire (fichier, disque dur, frame
buffer)
- une adresse virtuelle de base, et une taille
- les protections maximales de la region
- le type de partage { PRIVATE, SHARED }
- des pointeurs vers un ensemble de méthodes :
page_fault_handler, is_swappable, swapout_notification,
swapin_notification. Ces méthodes sont différentes pour
chaque type de région virtuelle (cf précédent mail dans
kos-dev).
Comme précisé dans la partie 11, une ressource correspond
globalement à un descripteur de fichier ouvert : si plusieurs team
ouvrent le même fichier, il y a alors une ressource par team pour ce
même fichier. Derrière cette ressource se trouve une shadow
ressource, unique pour chaque fichier, frame buffer, disque dur,
etc...
Lorsqu'un appel open() est réalisé, si la 'shadow resource' existe
déjà, alors on créé simplement une ressource pointant vers cette
shadow resource, sinon on créé la shadow resource et une
ressource. La ressource permet de maintenir les informations propres
à l'état de cette ressource pour la team qui l'appartient (position
dans le fichier...), tandis que la shadow resource permet de
maintenir des informations globales à toutes les teams, utiles pour
la gestion de la mémoire virtuelle. Chaque segment de mémoire
virtuelle est lié à une shadow resource, et non directement à une
resource.
Une shadow resource permet de maintenir les informations liées aux
différents mappings de la ressource concernée. Il y aurait donc une
liste des régions virtuelles associées à cette shadow resource. Un
page fault qui intervient sur une région virtuelle fait appel au
driver de cette région virtuelle, qui pourra alors utiliser la
shadow resource pour charger des données en mémoire.
Les entités shadow resource/virtual region/address space et les
différents drivers de segments semblent suffisantes pour implémenter
la gestion de la mémoire virtuelle.
En ce qui concerne le swapping, nous n'allons pas comme sous Linux
actuellement swapper des régions virtuelles. Nous allons raisonner à
partir des pages physiques, ce qui implique pour chaque page
physique de maintenir tous les mappings virtuels associés. Or
maintenir ces informations peut devenir très couteux en terme de
mémoire, et nous allons donc partager au maximum des PT entre
différentes teams, afin de factoriser les reverses mappings.
struct reverse_mapping
{
pte_t *pte;
struct reverse_mapping *next;
};
A noter que le pointeur vers le pte présent dans cette structure est
un pointeur vers l'adresse du PTE en zone noyau, et non dans le
mirroring. Pour utiliser au maximum le partage de PTs, les
ressources mappées en mémoire seront le plus possible seules sur des
espaces de 4Mo. Une fois que celà n'est plus possible, alors on
mettra plusieurs ressources par zone de 4Mo, mais on perdra le
partage des PT.
13 - utils/mod_check
Le programme mod_check dans le répertoire utils/ checke en offline
les dépendances entre les modules (détection des unresolved symbols)
afin de ne pas attendre de booter Bochs ou une machine réelle pour
le voir. Par ailleurs, ce programme permet de générer des graphes de
dépendances avec 'dot' (package graphviz de ATT).
14 - config.h
Les fichiers loader/config.h et modules/config.h permettent
respectivement de changer la configuration du loader et des modules,
notamment au niveau du debugging (DEBUG ON BOCHS, DEBUG ON CONSOLE,
DEBUG ON SERIAL, etc..). Ils remplacent les variables du fichier
MkVars.
15 - Dependances Makefile
Generation des dependances .c->.h automatique
--
d2