Changes between Version 66 and Version 67 of AS6-TME-B5


Ignore:
Timestamp:
Feb 3, 2023, 4:39:10 PM (2 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AS6-TME-B5

    v66 v67  
    4646
    4747
    48 {{{#!html
    49 <font size=+7 color=orange> En travaux</font><br><br>
    50 }}}
    51 
    52 
    53 
    54 
    55 La majorité des réponses aux questions sont dans le cours, c'est voulu. Les questions suivent à peu près l'ordre du cours, elles sont simples, mais vous avez besoin de comprendre le cours pour y répondre :-)
     48
     49La majorité des réponses aux questions sont dans le cours, c'est voulu. Les questions suivent à peu près l'ordre du cours, elles sont simples, mais vous avez quand même besoin de comprendre le cours pour y répondre :-)
    5650Quand une question vous demande si quelque chose est vrai ou faux, ne répondez pas juste "oui" ou "non », mais justifiez vos réponses avec une petite phrase. Le but de ces questions est d'évaluer vos connaissances, donc plus vous êtes précis, mieux c'est. Vous avez un corrigé que vous devez consulter pour vous autocorriger, mais pour qu'il soit utile, lisez-le après avoir cherché vous-même les réponses.
    5751Dans certains cas, ce ne sera pas simple, mais tentez quand même une réponse, même si vous savez que c'est faux, car ce sera plus simple de comprendre la réponse.
     
    7064{{{#!protected ------------------------------------------------------------------
    7165'''
    72  * Un processus est un programme en cours d'exécution. Dans cette définition, le programme c'est le fichier qui contient le code.
     66 * Un processus est un programme en cours d'exécution. Dans cette définition, le programme c'est seulement le fichier qui contient le code.
     67 * Pour le système d'exploitation, c'est un conteneur de ressources permettant l'exécution d'un programme. C'est-à-dire, l'ensemble des ressources nécessaires : un espace d'adressage pour le code et les données, des fichiers, des ports réseaux et des threads, etc. Dans cette UE, on ne voit pas vraiment la notion de processus puisqu'on a une seule application, pas d'espace d'adressage virtuel, pas de système de fichiers, on est donc dans un cas très simplifié.
    7368'''
    7469}}}
     
    9893'''
    9994}}}
    100 1. Un thread de processus informatique représente une exécution de ce processus. Il est défini par une pile d'exécution pour ses fonctions, un état des registres du processeur et des propriétés comme un état d'exécution (RUNNING, READY, DEAD, et d'autres que nous verront plus tard). Combien de threads a-t-on par processus au minimum et au maximum ?
     951. Un thread de processus informatique représente un fil d'exécution de ce processus. Il est défini par une pile d'exécution pour ses fonctions, un état des registres du processeur et des propriétés comme un état d'exécution (RUNNING, READY, DEAD, et d'autres que nous verront plus tard). Combien de threads a-t-on par processus au minimum et au maximum ?
    10196{{{#!protected ------------------------------------------------------------------
    10297'''
     
    113108{{{#!protected ------------------------------------------------------------------
    114109'''
    115  * Bien sûr, rien ne l'en empêche, c'est généralement le cas. Si vous appeler par exemple `printf()` dans votre thread, c'est un appel de fonction.
     110 * Bien sûr, rien ne l'en empêche, c'est généralement le cas. Si vous appelez par exemple `printf()` dans votre thread, c'est un appel de fonction.
    116111'''
    117112}}}
     
    205200'''
    206201 * Pour notre système, c'est dans un tableau présent dans la structure de données du thread (`struct thread_s`).
    207  * C'est une fonction en fonction en assembleur parce qu'elle est spécifique au processeur, on ne pourrait pas l'écrire en C.
     202 * C'est une fonction en assembleur parce qu'elle est spécifique au processeur, on ne pourrait pas l'écrire en C.
    208203 * Elle prend en argument un pointeur vers le tableau de sauvegarde. C'est un prototype générique qui fait partie de la HAL (Hardware Abstraction Layer).
    209204 * Elle rend 1 quand elle vient juste de faire la sauvegarde du contexte du thread en cours.
     
    249244   * Terminaison : `int thread_exit (void *retval);`\\
    250245     Le thread courant passe de l'état `RUNNING` (donné par l'ordonnanceur) à l'état `DEAD`\\
    251  * Nous verrons d'autres fonctions (p.ex. `mutex_lock()`) et d'autres états de threads (p.ex. `WAIT` ou `ZOMBI`)
     246 * Nous verrons d'autres fonctions (p. ex. `mutex_lock()`) et d'autres états de threads (p. ex. `WAIT` ou `ZOMBI`)
    252247'''
    253248}}}
     
    268263'''
    269264 * Lorsque l'ordonnance élit un thread pour la première fois,
    270    * il va débuter par `thread_bootstrap()` parce que c'est l'adresse de cette fonction qui a été mis dans **`$31`**,
     265   * il va débuter par `thread_bootstrap()` parce que c'est l'adresse de cette fonction qui a été mise dans **`$31`**,
    271266   * aucun registre GPR ne contient encore rien de significatif, sauf bien sûr **`$sp`** le pointeur de pile,
    272267   * `thread_bootstrap()` appelle `thread_launch()` pour sauter dans la fonction `thread_start()` avec l'instruction `eret`, il faut que `$c0_sr` soit tel que l'exécution d'`eret` nous amène en mode user, interruptions autorisées.
     
    318313}}} 
    319314 * Comme vous pouvez le voir, dans ces fonctions, on commence par changer l'état du thread et après on appelle `sched_switch()`.
    320  * Pour le moment c'est un simple changement d'état avant l'appel à `sched_switch()`, mais plus tard, il y aura d'autres opérations, pour la gestion des listes d'attente des ressources partagées ou la gestion des terminaisons de threads dont d'autres attendent la terminaison (avec `thread_join`).
     315 * Pour le moment, c'est un simple changement d'état avant l'appel à `sched_switch()`, mais plus tard, il y aura d'autres opérations, pour la gestion des listes d'attente des ressources partagées ou la gestion des terminaisons de threads dont d'autres attendent la terminaison (avec `thread_join`).
    321316'''
    322317}}}
     
    416411'''
    417412 * Deux possibilités :
    418    1. Soit le noyau abandonne le service et rend une erreur au thread pour l'informer que le service ne peut pas être rendu, et donc que le thread doit re-tenter sa chance plus tard ou faire autre chose. Pour l'analogie, vous dites à votre client de partir et de, s'il veut, revenir plus tard ou pas.
     413   1. Soit le noyau abandonne le service et rend une erreur au thread pour l'informer que le service ne peut pas être rendu, et donc que le thread doit retenter sa chance plus tard ou faire autre chose. Pour l'analogie, vous dites à votre client de partir et de, s'il veut, revenir plus tard ou pas.
    419414   2. Soit le noyau demande un changement de thread avec `thread_yield()` pour faire quelque chose d'utile pour un autre thread. Pour l'analogie, vous dites à votre client d'attendre et vous allez faire autre chose. Le client attend et tente de rentrer dès qu'un autre client sort du restaurant. Notez que dans cette analogie, il n'y a pas de file d'attente, le dernier client arrivé sera peut-être le premier servi.
    420415 * Dans la version actuelle du code, le thread qui attend la ressource reste dans l'état READY et donc il sera élu par l'ordonnanceur quand son tour viendra pour tester à nouveau la ressource et la prendre si elle est disponible, sinon il subit à nouveau un `thread_yield()`.
     
    428423
    429424
    430 Pour la suite de la séance, récupérez l'archive du [attachment:s3.tgz tp3 (nommé s3)] et placez là à côté des tp1 et tp2. Le code est fonctionnel, vous pouvez le tester. Je ne vous fais pas modifier, ou pire écrire, la gestion des threads, mais je vous invite à lire le code, c'est très commenté. Les principaux fichiers modifiés sont `kernel/hcpua.S` pour les fonctions `thread_load()`,  `thread_save()` et `thread_launch()` (`app_launch()` a disparu, elle n'est plus utile). Des fichiers sont nouveaux  : `kernel/kthread.h` qui contient le code de `thread_create_kernel()`, `thread_yield()`, `thread_exit()`, `sched_switch()` et quelques autres. `common/thread.h' qui contient les prototypes de fonctions communes au noyau et à l'utilisateur et 'ulib/thread.c' qui contient aussi les fonctions `thread_create()`, `thread_yield(), `thread_exit()` mais avec des appels système. Je vous invite vraiment à lire le code, c'est un bon exercice de lire le code des autres, croyez-moi.
     425Pour la suite de la séance, récupérez l'archive du tp3 et placez là à côté des tp1 et tp2. Le code est fonctionnel, vous pouvez le tester. Je ne vous fais pas modifier, ou pire écrire, la gestion des threads, mais je vous invite à lire le code, c'est très commenté. Les principaux fichiers modifiés sont `kernel/hcpua.S` pour les fonctions `thread_load()`,  `thread_save()` et `thread_launch()` (`app_launch()` a disparu, elle n'est plus utile). Des fichiers sont nouveaux  : `kernel/kthread.h` qui contient le code de `thread_create_kernel()`, `thread_yield()`, `thread_exit()`, `sched_switch()` et quelques autres. `common/thread.h' qui contient les prototypes de fonctions communes au noyau et à l'utilisateur et 'ulib/thread.c' qui contient aussi les fonctions `thread_create()`, `thread_yield(), `thread_exit()` mais avec des appels système. Je vous invite vraiment à lire le code, c'est un bon exercice de lire le code des autres, croyez-moi.
    431426
    432427Vous pouvez voir la différence entre les fichiers du TME B2 et du TME B3
     
    467462{{{#!protected ------------------------------------------------------------------
    468463''
    469   * Il faut compter le nombre de cycle entre l'entrée dans le noyau (`kentry`) due à une IRQ du Timer et l'appel à `thread_load()` (il manque les cycles utilisés par `thread_load()`, on peut aussi prendre comme borne supérieur, le premier appel de la première fonction appelée dans le nouveau thread.
     464  * Il faut compter le nombre de cycles entre l'entrée dans le noyau (`kentry`) due à une IRQ du Timer et l'appel à `thread_load()` (il manque les cycles utilisés par `thread_load()`, on peut aussi prendre comme borne supérieure, le premier appel de la première fonction appelée dans le nouveau thread.
    470465  * Pour une mesure précise, il faut utiliser le ficher `trace0.s` et compter le temps entre `kentry` et l'instruction `eret` lors du traitement d'une IRQ du Timer.
    471466''
     
    632627Pour le comprendre, nous allons partir d'un exemple illustré par le schéma ci-dessous :
    633628* **`T0`** appelle tty_read() qui cède le processeur à **`T1`** en l'absence de frappes.
    634 * Le thread **`T0`** demande des lectures à chaque qu'il a le processeur, **`T1`** prend le temps qui lui est donné jusqu'à l'IRQ du TIMER.
     629* Le thread **`T0`** demande des lectures à chaque fois qu'il a le processeur, **`T1`** prend le temps qui lui est donné jusqu'à l'IRQ du TIMER.
    635630* Si l'utilisateur frappe beaucoup de touches pendant que **`T0`** n'a pas le processeur. Les caractères lus doivent être stockés quelque part dans le contrôleur de TTY pour ne pas les perdre. Mais si cette mémoire est trop petite, on risque de perdre des caractères.
    636631