[Kos-dev] Reentrance de reschedule : un solution ?

Thomas Petazzoni kos-dev@enix.org
Tue, 26 Jun 2001 10:35:49 +0200


> Non, David, tu as parfaitement raison sur le fait qu'un BH ne doit pas être
> bloquant, parce qu'il serait tout bonnement incompréhensible et injuste
> qu'une tâche quelconque qui a eu le malheur d'être interrompue par un ISR
> puis un BH soit bloquée par le BH parce que ce dernier utiliserait une
> ressource bloquante (cette même ressource n'ayant strictement rien à avoir
> avec la tâche victime...). D'où l'idée effectivement d'un thread mandataire
> (mandaté pour un BH bloquant, c'est bien là où tu veux en venir, j'imagine)
> qui serait bloqué par ce BH plutôt que la tâche victime.

je suis tout a fait conscient de ce probleme des BH bloquants, mais
personellement je pensais que nous allions utiliser des threads noyau a
part entiere pour ces bottom halves. Je pensais qu'on aurait un set de
thread prealloues (un pool) et qu'on viendrait piocher dedans pour
associer un thread a un traitement d'interruption. 
ou alors on pourrait imaginer : on a un thread pour chaque interruption,
lorsque l'irq est levee, le handler place de cote les donnees critiques,
puis met le thread a l'etat eligible. le thread sera donc elu un jour ou
l'autre, et a la fin du traitement de toutes les donnees (il peut y
avoir eu plusieurs irqs correspondant a ce thread avant que le
traitement ne soit execute) il se place lui meme en etat endormi.
ex : pour l'irq clavier, on a un handler qui prend la donnee dans le
buffer, et le place dans un buffer de scancode. des qu'un scancode est
recu, le thread noyau correspondant a cet irq est place a l'etat
eligible. lorsque ce thread est elu, il va traiter TOUS les elements du
buffer pour les convertir en codes ASCII.

avantages : plus le probleme de blocage des BH, car ils sont eux memes
des thread a part entiere, et en plus pas besoin d'allouer/desallouer
des threads, meme provenant d'un pool : il suffit de placer le thread
correspondant a l'etat eligible, et zou le traitement sera lance !

personnellement je trouve que c'est la solution la plus belle.
techniquement je pense que c'est faisable, mais il peut y avoir des
failles. a vous de les trouver :)

je resume ma solution, pour etre sur de bien me faire comprendre (je
m'exprime mal parfois, alors maintenant je fais attention d'etre le plus
precis possible).

pour chaque IRQ, on a
	- un prehandler (contenu dans idt/idtasm.S) qui ne fait presque rien :
sauvegarde des registres, appel du handler, envoi du EOI, restauration
des registres et IRET
	- un handler (enregistre au moyen de la fonction
register_interrupt_handler)
	- un thread qui est en fait une boucle infinie de traitement, mais qui
a chaque iteration de boucle se place a l'etat non eligible et fait un
reschedule. ce thread peut etre considere comme un BH, dans la mesure ou
il prend en charge des traitements qui n'ont pas besoin d'etre effectue
juste apres l'interruption.

quand une IRQ arrive, le handler place le thread correspondant a cette
interruption a l'etat eligible, et peut retourner. le systeme tourne, et
au bout d'un certain temps, notre thread sera elu. il fera un petit tour
de sa boucle infinie, pour traiter les donnees puis se place a l'etat
non eligible avant de faire un reschedule.

je pense que c'est assez clair.

> Evidemment on peut supposer un cas très spécial où si on se trouve dans une
> tâche victime d'un BH bloquant, un thread mandataire prendra le relais pour
> permettre à la tâche victime de continuer et ce serait le thread mandataire
> qui serait bloqué. Bien sûr, cela suppose que les primitives bloquantes
> sachent si oui ou non elles tournent dans une tâche victime ou fautive. Si
> elle est victime, on duplique le thread pour en bloquer un et laisser
> continuer l'autre (je suppose que l'on a une réserve de thread prêt à
> l'emploi pour ces cas-là). Si elle est fautive, c'est que cette tâche doit
> être bloquée. Les tâches interrompues par les BH tombent dans le cas des
> victimes. Allez c'est un peu fumeux, je vous l'accorde ;-).

ouaip je trouve ca plutot complique, c'est pourquoi je proposais la
chose qui precede. 

> Pour résumer, mon idée était qu'un BH n'est pas forcément bloquant, donc
> l'utilisation systématique d'un thread mandataire constitue un "overhead"
> inutile. Ce thread mandataire ne serait utilisé qu'en cas de nécessité
> expresse, i.e, que si le BH se bloque - comme de tout façon, il doit bloquer
> une tâche, autant créer alors ce thread mandataire à ce moment là, ça
> n'ajoutera pas plus d'"overhead" que si on le faisait systématiquement à
> chaque BH. C'est un peu le même principe que les exceptions - en particulier
> les défauts de page, par exemple : l'artillerie lourde de la pagination
> n'intervient qu'"exceptionnellement". Le thread mandataire serait donc la
> réponse exceptionnelle à un BH bloquant.

la question d'overhead n'existe plus avec ma solution dans la mesure ou
les threads sont alloues au moment de l'enregistrement d'un handler pour
l'IRQ. il y a une seule chose a faire pour que le thread s'execute : un
changement d'etat, operation qui tient en une instruction !

> Pour en revenir aux IPL, il se trouve que les PC basés sur l'architecture
> intel 32-bit des 86 utilise un chipset (PIC) pour les interruptions assez
> basique en fin de compte car le niveau de priorité est figé. Le timer 0 qui
> est l'IRQ #0 a une priorité maximum par défaut sur les autres. Certes, en
> étant malin et en utilisant astucieusement les port de registres du PIC
> (0x20,0x21,0xA0,0xA1) on pourrait simuler les IPL, mais ce serait encore
> très limité.

oui effectivement gerer les priorites avec le PIC est assez lamentable,
et le faire a la main pourrait pourra surement etre utile.

> Je ne vous recommande pas de se lancer dans ce jeu là - cela constituerait
> des "overheads" probablement pas rentables.

donc tu penses qu'il vaut mieux laisser les priorites du PIC faire leur
bazar, en prenant en compte le fait que nos handlers seront courts en
execution.

> En revanche, la gestion des IPL dans les BH, pourquoi pas ? ce n'est ni plus
> ni moins qu'une façon d'ordonner l'exécution des BH.

d'accord.

personnellement je vois un inconvenient a ma solution : le handler de
timer 0 ne pourra pas utiliser de BH, car sinon on va tourner en rond !
c'est ce handler la qui elit le prochain thread, et si le thread qui
doit elire le prochain thread est a l'etat endormi, ca va pas etre
possible (en reprenant la fameuse formule des Motives).

mais a part ca ma solution parait envisageable. a vous de la
critiquer... ou de ne pas la critiquer :)

thomas

-- 
PETAZZONI Thomas
thomas.petazzoni@meridon.com     UIN : 34937744
Projet KOS : http://kos.enix.org
Page Perso : http://www.enix.org/~thomas/