219 | | 1. Quand un thread **TS** perd le processeur pour une raison X à la date `T`, il entre dans le noyau par kentry, puis il y a une séquence d'appel de fonction jusqu'au `thread_load()` du thread **TE** entrant. Lorsqu'on sort de `thread_load()`, on est dans le nouveau thread **TE**. Plus tard, le thread **TS** sera élu et regagnera le processeur en sortant d'un `thread_load()`, puis on sortira de la séquence des appels qu'il y avait eu à la date `T`. Expliquez, grace à la description de ce comportement, pourquoi on ne sauve pas les registres temporaires dans le contexte des threads. |
220 | | {{{#!protected ------------------------------------------------------------------ |
221 | | ''' |
222 | | * |
223 | | ''' |
224 | | }}} |
225 | | 1. |
226 | | {{{#!protected ------------------------------------------------------------------ |
227 | | ''' |
228 | | * |
229 | | ''' |
230 | | }}} |
231 | | 1. |
232 | | {{{#!protected ------------------------------------------------------------------ |
233 | | ''' |
234 | | * |
235 | | ''' |
236 | | }}} |
237 | | 1. |
238 | | {{{#!protected ------------------------------------------------------------------ |
239 | | ''' |
240 | | * |
241 | | ''' |
242 | | }}} |
243 | | 1. |
244 | | {{{#!protected ------------------------------------------------------------------ |
245 | | ''' |
246 | | * |
247 | | ''' |
248 | | }}} |
249 | | 1. |
250 | | {{{#!protected ------------------------------------------------------------------ |
251 | | ''' |
252 | | * |
253 | | ''' |
254 | | }}} |
255 | | 1. |
| 219 | 1. Quand un thread **TS** perd le processeur pour une raison X à la date `T`, il entre dans le noyau par kentry, puis il y a une séquence d'appel de fonctions jusqu'à la fonction `thread_load()` du thread entrant **TE**. Lorsqu'on sort de ce `thread_load()`, on est dans le nouveau thread **TE**. Plus tard, le thread **TS** sera élu à son tour et gagnera à nouveau le processeur en sortant lui aussi d'un `thread_load()`. En conséquence, on sortira de la séquence des appels qu'il y avait eu à la date `T`.\\Expliquez, en vous appuyant sur la description du comportement précédent, pourquoi on ne sauve pas les registres temporaires dans le contexte des threads. |
| 220 | {{{#!protected ------------------------------------------------------------------ |
| 221 | ''' |
| 222 | * |
| 223 | ''' |
| 224 | }}} |
| 225 | 1. Dans le cours, nous suivons l'exécution du code au démarrage (vers le slide 37), nous pouvons voir que la fonction `kinit()` fait 3 choses importantes : (1) initialiser à `0` la section `BSS` (contenant les variables globales non explicitement initialisée dans le programme), (2) demander à l'architecture de s'initialiser et (3) lancer la première (et ici seule) application. |
| 226 | {{{#!c |
| 227 | void kinit (void) |
| 228 | { |
| 229 | kprintf (banner); |
| 230 | // 1 |
| 231 | extern int __bss_origin, __bss_end; |
| 232 | for (int *a = &__bss_origin; a != &__bss_end; *a++ = 0); |
| 233 | |
| 234 | // 2 |
| 235 | arch_init(20000); // init architecture ; arg=tick |
| 236 | |
| 237 | // 3 |
| 238 | extern thread_t _main_thread; // thread struct pour main() |
| 239 | extern int _start; // _start() point d'entrée app. |
| 240 | thread_create_kernel (&_main_thread, 0, 0, (int)&_start); |
| 241 | thread_load (_main_thread.context); |
| 242 | |
| 243 | kpanic(); |
| 244 | } |
| 245 | }}} |
| 246 | a. Où sont définis les symboles `__bss_origin`, `__bss_end`, `__main_thread`, `_start` et quels sont leur type ? |
| 247 | {{{#!protected ------------------------------------------------------------------ |
| 248 | ''' |
| 249 | * |
| 250 | ''' |
| 251 | }}} |
| 252 | a. Dites ce que sont les arguments `2` et `3` de `thread_kernel()` et pourquoi, ici, on les mets à `0`. |
| 253 | {{{#!protected ------------------------------------------------------------------ |
| 254 | ''' |
| 255 | * |
| 256 | ''' |
| 257 | }}} |
| 258 | a. Que se passe-t-il quand on sort de `thread_load()`et pourquoi avoir mis l'appel à `kpanic()` ? |
| 259 | {{{#!protected ------------------------------------------------------------------ |
| 260 | ''' |
| 261 | * |
| 262 | ''' |
| 263 | }}} |
| 264 | a. Dans quelle pile s'exécute la fonction `kinit()` ? dans quelle section est-elle ? Pourquoi elle n'est que temporaire ? |
| 265 | {{{#!protected ------------------------------------------------------------------ |
| 266 | ''' |
| 267 | * |
| 268 | ''' |
| 269 | }}} |
| 270 | a. Pour le chargement de thread `main()` avec `thread_load (_main_thread.context)`, on initialise les registres `$16` à `$23`, `$30`, `$c0_EPC`, est-utile ? Si oui pourquoi ? Si non, pourquoi faire ces initialisations ? |
| 271 | {{{#!protected ------------------------------------------------------------------ |
| 272 | ''' |
| 273 | * |
| 274 | ''' |
| 275 | }}} |
| 276 | 1. Dans le deuxième TME2, vous avez dû modifier le code `syscall_handler` (gestionnaire de syscalls) pour le rendre interruptible. En effet, lorsque l'application demande un service au noyau, mais que le noyau ne peut le rendre (comme la lecture d'une touche du clavier). |