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. |
|
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. |
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
Implantation
00194 { 00195 watchdog=FredThreadSpawn(20000,watchDogCode,(void*)0,(void**)0); 00196 } |
|
|
|
|
|
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. |
|
Seuls les threads créés par FredThreadSpawn() sont comptés. Ce compteur sert à détecter la terminaison du programme FRED (cf FredWaitTerminate() ). |
|
Elle n'est jamais vide du fait de l'existence du chien de garde watchdog |
|
Son rôle est d'éviter une file readyQ vide. Il ne fait que passer la main. ( cf. watchDogCode() ). |