Page principale   Modules   Liste des composants   Liste des fichiers   Composants   Déclarations  

Implantation des threads
[Implémentation de FRED]


Composants

struct  FredThreadDesc
 Descripteur de threads. Plus de détails...


Définitions des types

typedef FredThreadDesc FredThreadDesc
 Descripteur de threads.


Fonctions

void * leonCode (void *x)
 Le code du nettoyeur leon.

void LeonInit ()
 Initialisation de leon le nettoyeur.

void * watchDogCode (void *x)
 Le code du chien de garde watchdog.

void WatchDogInit ()
 Initialisation du chien de garde watchdog.

void QuantumHandler (int i)
 Traitement d'interruption de fin de quantum.

void TimeSharingInit (long int uS)
 Initialisation du temps partagé.

void FredThreadHarness ()
 Code initial des threads.

void MainThreadInit ()
 Initialisation du pseudo thread principal.


Variables

int volatile nbFredThreads
 Compteur du nombre de threads créés non terminés.

FredThread current
 Le thread actif.

FredQueue readyQ
 File d'attente des threads prêts.

FredQueue deadQ
 File d'attente des threads morts dont la pile est à libérer (réservée à leon le nettoyeur) Un thread terminant s'inscrit dans cette file et réveille leon s'il n'est pas déja réveillé ( cf leonCode() ).

FredThread leon
 Le nettoyeur leon.

FredQueue leonQ
 File d'attente de leon.

FredQueue endQ
 File d'attente de terminaison (réservée au mainThread ).

FredThreadDesc mainThreadBlock
 Descripeur du thread associé à la procédure main().

FredThread watchdog
 Thread chien de garde.

long int quantum
 Valeur du quantum en microseconde.


Documentation du type

typedef struct FredThreadDesc FredThreadDesc
 

Le champ FredThreadDesc::err est la sauvegarde de la variable globale errno qui contient le code d'erreur du programme. On la sauve et la restaure à chaque commutation de thread.


Documentation de la fonction

void FredThreadHarness  
 

Comme on ne peut retourner de façon normale de la procédure initiale d'un thread et comme le retour de celle-ci est le retour standard généré par le compilateur C, on utilise une procédure qui encadre (harnache) le démarrage et la fin d'un thread.



Implantation

Ce harnais appelle la procédure initiale du thread, récupére son résultat et délégue à leon la libération de la pile sans oublier les masquages et décomptages nécessaires.

00342 {/* on démarre masqué */
00343   FredThread old;
00344   /* lancer le décomptage */
00345   FredCountDownStart(quantum);
00346   /* démasquage */ 
00347   FredMaskOff(); 
00348   /* appel de la procédure initiale avec ou sans récupération dec résultat */
00349   if(current->resref){ /* on attend un résultat */
00350       *(current->resref)=current->entry(current->val);
00351 
00352   }else{    
00353       current->entry(current->val);
00354   }
00355   /* arrêt décomptage */
00356   FredCountDownStop(); 
00357   /* début exclusion mutuelle */
00358   FredMaskOn();
00359   /* réveil de leon */
00360   FredThreadWakeUp(&leonQ);
00361   /* 
00362     un thread ne peut libérer la mémoire
00363     dans laquelle il s'exécute. Il délègue cela 
00364     a leon  en s'inscrivant dans la
00365     file des threads défunts
00366   */
00367   FredThreadSuspend(&deadQ);
00368   /* on ne revient jamais la */
00369   FredAbort(" erreur fatale dans threadHarness");
00370 }

void* leonCode void *    x
 

Il est en charge de la libération de mémoire des threads morts et de la détection de terminaison.



Implantation

leon attend qu'un thread mourant le réveille dans sa file d'attente spécifique leonQ . Il trouve les threads décédés dans la file deadQ et libère la mémoire. Il décrémente le compte de threads nbFredThreads et détecte la terminaison. Dans ce cas, il réveille le thread principal si nécessaire.

00116 {
00117   FredThread t; 
00118   while(1){
00119     FredMaskOn();/* début d'exclusion mutuelle */
00120     /* libérer la mémoire des threads défunts */
00121     while((t=FredQueueGetFirst(&deadQ))){
00122       free(t->stack);free(t);
00123       nbFredThreads--;
00124     }
00125     /* si terminaison, on réveille le thread l'attendant */
00126     if(nbFredThreads==2)FredThreadWakeUp(&endQ);
00127     /* leon attend de nouveaux décès */
00128     FredThreadSuspend(&leonQ);
00129     FredMaskOff();
00130   }
00131   /* on ne revient jamais la */
00132   FredAbort(" erreur fatale dans leon");
00133 }

void LeonInit  
 



Implantation On lance leon après avoir initialiser les 2 files leonQ et deadQ .

00147 {
00148   FredQueueInit(&deadQ); /*  file vide */
00149   FredQueueInit(&leonQ); /*  file vide */
00150   leon=FredThreadSpawn(20000,leonCode,(void*)0,(void**)0);
00151 }

void MainThreadInit  
 



Implantation La procédure principale main() initialise la file d'attente de terminaison, son bloc descripteur et devient le thread courant. A partir de la, elle peut utiliser l'interface FRED comme tout thread normal (synchronisation etc..). Elle peut attendre la terminaison des autres threads via la file endQ (cf. FredWaitTerminate() ).

00518                      {
00519   /* file d'attente de disparition des autres threads */
00520   FredQueueInit(&endQ); /*  file vide */
00521   /* allocation decripteur */
00522   mainThread=&mainThreadBlock;
00523   /* thread actif */
00524   current=mainThread;
00525 }

void QuantumHandler int    i
 



Implantation On recycle en fin de readyQ le thread courant. On choisit le suivant qu'on relance avec un nouveau décomptage de quantum.

00214 {
00215   FredThread old;
00216   /* interruption de fin de quantum 
00217     on est masqué contre l'it quantum*/
00218   /* printf("+"); */
00219   FredMaskOn(); /* début d'exclusion mutuelle */
00220   current->err=errno; /* sauver errno */
00221   old=current;
00222   FredQueuePutLast(&readyQ,current);
00223   current=FredQueueGetFirst(&readyQ);
00224   if(current!=old)FredContextSwitch(old->ctx,current->ctx);
00225   /* 
00226     on reviendra ici lors de son réveil :
00227     on relance le décomptage du quantum
00228   */
00229   FredCountDownStart(quantum);
00230   errno=current->err;/* restaurer errno */
00231   FredMaskOff();/* fin d'exclusion mutuelle */
00232 }

void TimeSharingInit long int    uS
 



Implantation On initialise le quantum avec une valeur donnée et on attache le traitement d'interruption de fin de quantum au décompteur.

00245 {
00246   /* attaché à une interuption un traitant d'IT */
00247   FredCountDownAttach(QuantumHandler);
00248   /* valeur du quantum */
00249   quantum=uS;
00250 }

void* watchDogCode void *    x
 

Il évite d'avoir une file readyQ vide à traiter.



Implantation C'est un boucle infinie qui ne fait que passer la main à un autre thread prêt.

00176 {
00177   while(1){
00178     FredThreadYield();
00179     /* attraper les interruptions externes */
00180   }
00181   /* on ne revient jamais la */
00182   FredAbort(" erreur fatale dans chien de garde");
00183 }

void WatchDogInit  
 



Implantation

00194 {
00195   watchdog=FredThreadSpawn(20000,watchDogCode,(void*)0,(void**)0);
00196 }


Documentation de la variable

FredThread current
 

FredQueue deadQ
 

FredThread leon
 

Comme un thread terminant ne peut libérer la pile dans laquelle il s'exécute, ce travail est assuré par un thread spécifique de nettoyage : leon . Il attend qu'un thread mourant le réveille dans une file d'attente spécifique leonQ . Il trouve les threads décédés dans la file deadQ ( cf leonCode() ) Il assure aussi la détection de terminaison.

int volatile nbFredThreads
 

Seuls les threads créés par FredThreadSpawn() sont comptés. Ce compteur sert à détecter la terminaison du programme FRED (cf FredWaitTerminate() ).

FredQueue readyQ
 

Elle n'est jamais vide du fait de l'existence du chien de garde watchdog

FredThread watchdog
 

Son rôle est d'éviter une file readyQ vide. Il ne fait que passer la main. ( cf. watchDogCode() ).


Généré le Mon Jan 5 16:22:06 2004 par doxygen1.2.17