147 | | 1. Un thread se termine dans deux cas. Dans le premier cas, il fait appel à la fonction `thread_exit()`, explicitement dans la fonction principale du thread ou implicitement au retour de la fonction principale du thread. Cette terminaison volontaire peut être qualifiée de ''suicide''. C'est celle que nous avons vu en cours et que nous pouvons utiliser dans le code actuel. Le second cas de terminaison, non encore disponible, c'est quand un thread demande la terminaison d'un autre par `thread_cancel()`, ce qui provoque chez le thread désigné un `thread_exit()`. Cette terminaison imposée peut être qualifiée de ''meurtre''. Dans les cas du ''suicide'' et du ''meurtre'', pour quelle raison le thread qui va disparaitre, ne peut désallouer sa pile. |
148 | | {{{#!protected ------------------------------------------------------------------ |
149 | | ''' |
150 | | * |
151 | | ''' |
152 | | }}} |
153 | | 1. |
154 | | {{{#!protected ------------------------------------------------------------------ |
155 | | ''' |
156 | | * |
157 | | ''' |
158 | | }}} |
159 | | 1. |
160 | | {{{#!protected ------------------------------------------------------------------ |
161 | | ''' |
162 | | * |
163 | | ''' |
164 | | }}} |
165 | | 1. |
166 | | {{{#!protected ------------------------------------------------------------------ |
167 | | ''' |
168 | | * |
169 | | ''' |
170 | | }}} |
171 | | 1. |
172 | | {{{#!protected ------------------------------------------------------------------ |
173 | | ''' |
174 | | * |
175 | | ''' |
176 | | }}} |
177 | | 1. |
178 | | {{{#!protected ------------------------------------------------------------------ |
179 | | ''' |
180 | | * |
181 | | ''' |
182 | | }}} |
183 | | 1. |
184 | | {{{#!protected ------------------------------------------------------------------ |
185 | | ''' |
186 | | * |
187 | | ''' |
188 | | }}} |
189 | | 1. |
| 155 | |
| 156 | |
| 157 | == A.2. Questions sur l'implémentation |
| 158 | |
| 159 | |
| 160 | 1. Quelles sont les fonctions de l'API utilisateur des threads et les états de threads ? Indiquer les changements d'état provoqué par l'appel des fonctions de cette API. |
| 161 | {{{#!protected ------------------------------------------------------------------ |
| 162 | ''' |
| 163 | * |
| 164 | ''' |
| 165 | }}} |
| 166 | 1. La structure `thread_s` rassemble les propriété du thread, sa pile et le tableau de sauvegarde de son contexte. Cette structure est, dans l'état actuel du code` entièrement dans dans le segment des données globales de l'application. Pouvez-vous justifiez cette situation et en discuter ? |
| 167 | {{{#!protected ------------------------------------------------------------------ |
| 168 | ''' |
| 169 | * |
| 170 | ''' |
| 171 | }}} |
| 172 | 1. Le tableau de sauvegarde du contexte d'un thread est initialisé avec des valeurs qui seront chargées dans les registres du processeur au premier chargement du threads. Tous les registres n'ont pas besoin d'être initialisé avec une valeur. Seuls les registres `$c0_sr` (`$12` du coprocesseur système) , `$sp` (`$29` des GPR) et `$ra` (`$31` des GPR) ont besoins d'avoir une valeur choisie. Pourquoi ? |
| 173 | {{{#!protected ------------------------------------------------------------------ |
| 174 | ''' |
| 175 | * |
| 176 | ''' |
| 177 | }}} |
| 178 | 1. `$c0_sr` est initialisé avec `0x413`, dite pourquoi. |
| 179 | {{{#!protected ------------------------------------------------------------------ |
| 180 | ''' |
| 181 | * |
| 182 | ''' |
| 183 | }}} |
| 184 | 1. La fonction `sched_switch()` appelle d'abord l'électeur de thread qui choisit le thread entrant (qui gagne le processeur), puis `sched_switch()` sauve le contexte du thread sortant (qui perd le processeur) et charge le contexte du thread entrant, enfin `sched_switch()` change l'état du thread entrant à `RUNNING`. `sched_switch()` est appelée par `thread_yield()`. Pouvez expliquer pourquoi avoir créé `sched_switch()` ? Ce n'est pas évident au premier abord, mais il y a une raison. |
| 185 | {{{#!c |
| 186 | void sched_switch (void) { // |
| 187 | int th_curr = thread_current_idx; // n° du thread courant dans thread_tab |
| 188 | int th_next = sched_elect (); // demande le numéro du prochain thread |
| 189 | if (th_next != th_curr) { // Si c'est le même thread, ne rien faire ! |
| 190 | if (thread_save (thread_tab[th_curr]->context)) { // sauve le ctx du thread sortant et rend 1 |
| 191 | thread_current_idx = th_next; // mise à jour de thread_current_idx |
| 192 | thread_load (thread_tab[th_next]->context); // chargement de contexte & sortie par jr $31 |
| 193 | } // donc de thread_save() mais qui rend 0 |
| 194 | } |
| 195 | thread_tab[thread_current_idx]->state= TH_STATE_RUNNING; // the thread choisi est dans l'état |
| 196 | } |
| 197 | int thread_yield (void) { |
| 198 | thread_tab[thread_current_idx]->state = TH_STATE_READY; // état futur du thread sortant |
| 199 | sched_switch (); // changement de threads (ou pas) |
| 200 | return 0; |
| 201 | }}} |
| 202 | {{{#!protected ------------------------------------------------------------------ |
| 203 | ''' |
| 204 | * |
| 205 | ''' |
| 206 | }}} |
| 207 | 1. Pour quelle raison, ne sauver que les registres persistants dans le contexte des threads ? |
| 208 | {{{#!protected ------------------------------------------------------------------ |
| 209 | ''' |
| 210 | * |
| 211 | ''' |
| 212 | }}} |
| 213 | 1. Quand un thread est élu pour la prem |