Changes between Version 38 and Version 39 of AS6-TME-B5


Ignore:
Timestamp:
Feb 22, 2022, 3:02:06 PM (3 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AS6-TME-B5

    v38 v39  
    388388
    389389**kernel/harch.c**
     390
     391  *
    390392{{{#!c
    391393int tty_read (int tty, char *buf, unsigned count)
     
    409411Le schéma ci-dessous illustre le problème.
    410412 [[Image(htdocs:img/IRQTTY_1.png,nolink,height=200)]]
     413Le thread **`T0`** demande des lectures, `T1` prend le temps qui lui est donné jusqu'à l'IRQ du TIMER, je vous propose de lire le code en détail.
     414
     415**uapp/main.c**
     416
     417 * Le code ci-dessous contient l'application. Nous avons 3 threads : `main`, `t0` et `t1`.
     418 * `main` et `t1` se contente d'afficher des messages sur le TTY0 et d'attendre (une attente active pour ralentir l'affichage des messages).
     419 * `t0` lit le clavier de TTY1
     420
     421{{{#!c
     422/*--------------------------------------------------------------------------------*\
     423   _     ___    __
     424  | |__ /'v'\  / /      \date        2022-02-22
     425  | / /(     )/ _ \     \copyright   2021-2022 Sorbonne University
     426  |_\_\ x___x \___/                  https://opensource.org/licenses/MIT
     427
     428\*--------------------------------------------------------------------------------*/
     429
     430#include <libc.h>
     431#include <thread.h>
     432
     433#define DELAY(n) for(int i=n;i--;) __asm__("nop");
     434
     435thread_t t0, t1;
     436
     437void * t0_fun (void * arg)
     438{
     439    char buf[64];
     440    for (int i = 0;; i++) {
     441        fprintf (1, "entrez un truc : ");
     442        fgets (buf, sizeof(buf), 1);
     443        fprintf (1, "%s\n", buf);
     444    }
     445    return NULL;
     446}
     447
     448void * t1_fun (void * arg)
     449{
     450    for (int i = 0;; i++) {
     451        fprintf (0, "[%d] t1 is alive (%d) : %s\n", clock(), i, (char *)arg);
     452        DELAY(1000000);
     453    }
     454    return NULL;
     455}
     456
     457int main (void)
     458{
     459    thread_create (&t1, t1_fun, "bonjour");
     460    thread_create (&t2, t2_fun, NULL);
     461    for (int i = 0;; i++) {
     462        fprintf (0, "[%d] app is alive (%d)\n", clock(), i);
     463        DELAY(1000000);
     464    }
     465    return 0;
     466}
     467}}}
     468
     469**ulib/libc.c**
     470
     471 * La fonction `fgets()` est dans la **libc**, c'est une fonction bloquante du point de vue de l'utilisateur. Il l'appelle pour lire `count` caractères sur le TTY n°`tty` et les enregistre dans `buf`.
     472 * `fgets()` demande 1 caractère à la fois et elle le revoit sur l'écran (c'est un ''loopback'') pour que l'utilisateur sache que son caractère a été pris en compte.
     473 * Il y a quelques subtilités dues au fait que lorsque vous taper sur ''**enter''**, le clavier envoie deux caractères '\r' (`13` = ''carriage return'') et '\n' (`10` = ''line feed''), on jette `\r`. En outre, on gère le `back sapce` et le `delete` (à qui on donne le même comportement pour simplifier). Je vous laisse essayer de comprendre pour le plaisir.
     474 * Quand `fgets()` appelle `read()`, cela fait l'appel système `SYSCALL_READ`.
     475
     476{{{#!c
     477int read(int fd, void *buf, int count)
     478{   
     479    return syscall_fct( fd, (int)buf, count, 0, SYSCALL_READ);
     480}   
     481   
     482int write(int fd, void *buf, int count)
     483{   
     484    return syscall_fct( fd, (int)buf, count, 0, SYSCALL_WRITE);
     485}
     486
     487int fgets (char *buf, int count, int tty)
     488{
     489    // to make the backspace, we use ANSI codes : https://www.wikiwand.com/en/ANSI_escape_code
     490    char *DEL = "\033[D \033[D";                // move left, then write ' ' and move left
     491    int res = 0;
     492    count--;                                    // we need to add a NUL (0) char at the end
     493    char c=0;
     494   
     495    while ((count != 0) && (c != '\n')) {       // as long as we can or need to get a char
     496
     497        read (tty, &c, 1);                      // read only 1 char
     498        if (c == '\r')                          // if c is the carriage return (13)
     499            read (tty, &c, 1);                  // get the next that is line feed (10)
     500   
     501        if ((c == 8)||(c == 127)) {             // 8 = backspace, 127 = delete
     502            if (res) {                          // go back in the buffer if possible
     503                write (tty, DEL, 7);            // erase current char
     504                count++;                        // count is the remaining place
     505                buf--;                          // but is the next address in buffer
     506                res--;
     507            }
     508            continue;                           // ask for another key
     509        } else
     510            write (tty, &c, 1);                 // loop back to the tty
     511
     512        *buf = c;                               // write the char into the buffer
     513        buf++;                                  // increments the writing pointer
     514        count--;                                // decrements the remaining space
     515        res++;                                  // increments the read char
     516    }
     517    *buf = 0;                                   // add a last 0 to end the string
     518
     519    return res;                                 // returns the number of char read
     520}
     521}}}
     522
     523**kernel/ksyscall.c**
     524
     525 * Je ne met pas toutes les étapes de l'appel du gestionnaire de syscall, vous avez ici le vecteur de syscall qui montre bien que l'on appelle la fonction du noyau `tty_read()` dont vous avez le code un peu plus haut.
     526
     527{{{#!c
     528void *syscall_vector[] = {
     529    [0 ... SYSCALL_NR - 1 ] = unknown_syscall,   /* default function */
     530    [SYSCALL_EXIT         ] = exit,
     531    [SYSCALL_READ         ] = tty_read,
     532    [SYSCALL_WRITE        ] = tty_write,
     533    [SYSCALL_CLOCK        ] = clock,
     534    [SYSCALL_THREAD_CREATE] = thread_create_kernel,
     535    [SYSCALL_THREAD_YIELD ] = thread_yield,
     536    [SYSCALL_THREAD_EXIT  ] = thread_exit,
     537    [SYSCALL_SCHED_DUMP   ] = sched_dump,
     538};
     539}}}
     540