diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..28a6a5e50e3c50b91d4345a55179b13785efa478 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +install: "pip install -q -r requirements.txt" +language: python +python: + - "3.6" +# command to run tests +script: bash travis.sh diff --git a/Exercices/Programmes/prog-1.rst b/Exercices/Programmes/prog-1.rst index 1cf026f9b424161a3481a904772c21382d1b26fb..dabb9094781cc0b86e626d9cb8e46830cd5ef83e 100644 --- a/Exercices/Programmes/prog-1.rst +++ b/Exercices/Programmes/prog-1.rst @@ -7,8 +7,8 @@ Exercices -1. Exercices en bash --------------------- +1. Exercices de manipulation du shell +------------------------------------- Pour rappel, quelques commandes de base dans le shell pour gérer les dossiers et fichiers: @@ -32,8 +32,47 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans #. Retournez dans le répertoire parent de ``my_dir`` et copiez le dossier complet ``my_dir`` dans ``my_dir_2``. #. Effacez le dossier entier ``my_dir`` en une seule commande (utilisez `rm(1)`_). -2. Questions de base --------------------- +Vous trouverez également sur `le cours LSINF1252 sur inginious <https://inginious.info.ucl.ac.be/course/LSINF1252>`_ les exercices suivants : + +#. Utilisation de la commande `grep(1)`_ : https://inginious.info.ucl.ac.be/course/LSINF1252/s1_grep +#. Utilisation des pipes : https://inginious.info.ucl.ac.be/course/LSINF1252/s1_pipes +#. Utilisation de la commande `tar(1)`_ : https://inginious.info.ucl.ac.be/course/LSINF1252/s1_tar +#. Capture the flag (1): https://inginious.info.ucl.ac.be/course/LSINF1252/s1_ctf1 +#. Capture the flag (2): https://inginious.info.ucl.ac.be/course/LSINF1252/s1_ctf2 + +.. only:: staff + + - Il faudrait quand même qu'ils l'aient fait une fois avant le TP + - Faire l'exercice sur les pipes avant de faire le CTF + - Si un élève est bloqué, relire les dernières consignes, si rien d'explicite taper "./.suite" + - Quand les consignes disent de + dire quelque chose de spécifique = "echo parole | ./interlocuteur" + parler à quelqu'un = "./interlocuteur" + - Faire TRÈS attention à taper correctement l'identifiant inginious au début, sinon ce n'est qu'en ayant fini le CTF qu'ils verront l'erreur + - Attention, quand on tape la réponse finale dans inginious, elle est écrite sous la forme "[hash] -", il faut copier-coller la sortie en entier, le tiret compris, pas juste le hash + - L'exercice est individuel, la réponse dépend de l'identifiant de l'étudiant + - En cas de problème avec le code de vérification (il n'y en a théoriquement pas, mais qui sait) le tuteur peut générer la clé à entrer dans inginious comme suit (depuis la racine) : + cd .ressources/script + ./init lIdentifiantInginious + ./next + ./next + ./next + ./next + ./next + + +2. Découverte du C +------------------ + +Certains côtés du C sont très proches du langage Java que vous connaissez déjà . Ce n'est pas surprenant +puisque Java a été conçu avec le langage C comme base. Les inventeurs de Java ont ajouté tout ce qui +était nécessaire pour supporter les objets et ont retiré la gestion explicite de la mémoire. Les premiers +exercices `inginious en C <https://inginious.info.ucl.ac.be/course/LSINF1252>`_ sont très proches de ceux +que vous aviez réalisé en Java. + +#. Calcul de la valeur absolue d'une entier: https://inginious.info.ucl.ac.be/course/LSINF1252/absolute_value +#. Calcul de la factorielle d'un nombre entier: https://inginious.info.ucl.ac.be/course/LSINF1252/factorial +#. Recherche d'un élément dans un tableau d'entiers: https://inginious.info.ucl.ac.be/course/LSINF1252/tab_find #. Compilez et exécutez le code suivant. Expliquez ce que fait l'appel à `printf(3)`_. @@ -83,7 +122,7 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans .. note:: - voir note du cours. + voir notes de cours. #. Expliquez à quoi sert l'option ``-Wall`` de ``gcc``. @@ -100,11 +139,14 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans .. note:: - ``-Wall``: warning si une fonction ne renvoi pas de valeur. Il faut donc ajouter ``return 0;`` à la fin de la ``main``. + ``-Wall``: warning si une fonction ne renvoie pas de valeur. Il faut donc ajouter ``return 0;`` à la fin de la ``main``. -#. Compiler le code suivant (sans les options ``-Wall`` et ``-Werror``). Expliquez ce que sont les arguments de la fonction ``main``. Expliquez ce que fait `atoi(3)`_ (voir `strtol(3)`_ pour une fonction similaire). Exécutez ensuite le code avec ou sans arguments. Qu'observez-vous ? Comment se protéger du fait qu'un utilisateur ne va pas forcément rentrer le bon nombre d'arguments ? - .. code-block:: c +.. only:: staff + + #. Compilez le code suivant (sans les options ``-Wall`` et ``-Werror``). Expliquez ce que sont les arguments de la fonction ``main``. Expliquez ce que fait `atoi(3)`_ (voir `strtol(3)`_ pour une fonction similaire). Exécutez ensuite le code avec ou sans arguments. Qu'observez-vous ? Comment se protéger du fait qu'un utilisateur ne va pas forcément rentrer le bon nombre d'arguments ? + + .. code-block:: c #include <stdlib.h> int main(int argc, const char *argv[]) @@ -113,8 +155,6 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans printf("%d\n", a); } - .. only:: staff - .. note:: ``argc`` = nombre d'arguments. @@ -122,9 +162,10 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans ``atoi`` = transforme une chaine de caractère en un entier. Le programme renvoi une segmentation fault lorsque l'on ne passe pas d'argument. Il faut donc utiliser ``argc`` pour tester que l'on a le bon nombre d'argument. -#. Ecrivez un programme qui va itérer (avec une boucle ``for`` et une boucle ``while``) et afficher tous les arguments qui lui sont passés à la sortie standard. - .. only:: staff +.. only:: staff + + #. Ecrivez un programme qui va itérer (avec une boucle ``for`` et une boucle ``while``) et afficher tous les arguments qui lui sont passés à la sortie standard. .. note:: @@ -148,7 +189,7 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans $ if ! ./false; then echo "false fonctionne"; fi false fonctionne - Bash permet aussi de faire des ``else``. Trouvez comme faire en regardant ce `lien <http://tldp.org/LDP/abs/html/tests.html>`_. + Bash permet aussi de faire des ``else``. Trouvez comment faire en regardant ce `lien <http://tldp.org/LDP/abs/html/tests.html>`_. .. only:: staff .. note:: @@ -172,20 +213,21 @@ Pour vous familiariser avec le shell, faites les petits exercices suivants dans } -3. Petits programmes --------------------- +.. only:: staff -#. Faites l'exercice sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/commandetest>`_ sur la commande `test(1)`_. + #. Faites l'exercice sur `commandetest <https://inginious.info.ucl.ac.be/course/LSINF1252/commandetest>`_ sur la commande `test(1)`_. - INGInious est un environnement qui permet de soumettre du code, et des tests sont automatiquement exécutés sur ce code. Cela vous permettra de vérifier que votre programme fonctionne. + INGInious est un environnement qui permet de soumettre du code, et des tests sont automatiquement exécutés sur ce code. Cela vous permettra de vérifier que votre programme fonctionne. - Pour vous connecter sur INGInious, utilisez votre login INGI que vous recevrez durant la première séance de TP. + Pour vous connecter sur INGInious, utilisez votre login INGI que vous recevrez durant la première séance de TP. -#. Faites de même pour la commande `expr(1)`_. On vous demande d'implémenter les expressions suivantes : ``+``, ``-``, ``*``, ``/`` et ``%``, mais cette fois-ci sans utiliser INGInious. Vous devriez tester votre programme vous-même et assurer le bon fonctionnement de celui-ci. + #. Faites de même pour la commande `expr(1)`_. On vous demande d'implémenter les expressions suivantes : ``+``, ``-``, ``*``, ``/`` et ``%``, mais cette fois-ci sans utiliser INGInious. Vous devriez tester votre programme vous-même et assurer le bon fonctionnement de celui-ci. - N'oubliez pas de respecter les valeurs de retour qui sont décrites dans les man-pages. + N'oubliez pas de respecter les valeurs de retour qui sont décrites dans les man-pages. -#. En utilisant le shell et un programme C, essayez de déterminer expérimentalement le nombre maximum d'arguments que vous pouvez passer à un programme C. Y a-t-il une limite à ce nombre d'arguments ? Si oui, d'où vient-elle et de quoi dépend-elle ? +.. only:: staff + + #. En utilisant le shell et un programme C, essayez de déterminer expérimentalement le nombre maximum d'arguments que vous pouvez passer à un programme C. Y a-t-il une limite à ce nombre d'arguments ? Si oui, d'où vient-elle et de quoi dépend-elle ? diff --git a/Exercices/Programmes/prog-2.rst b/Exercices/Programmes/prog-2.rst index c69829786868af869cfd298e897c7ff646f818e3..aa84c26eb68726d9eb728d6a1d28802d40b8576e 100644 --- a/Exercices/Programmes/prog-2.rst +++ b/Exercices/Programmes/prog-2.rst @@ -3,19 +3,54 @@ .. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ -1. Questions de base --------------------- -#. La zone mémoire utilisée diffère d'un type primitif à un autre. Ecrivez un code qui permet d'afficher le nombre de bytes utilisés sur un système 64 bits (une machine des salles) et une machine 32 bits (sirius, voir section :ref:`outils:ssh`) pour représenter un ``int``, ``long``, ``void *``, ``char *``, ``size_t`` et ``uint64_t``. Expliquez les différences. +Questions INGINIOUS +------------------- + +#. Faites l'exercice relatif à `printf(3)`_ sur INGINIOUS : https://inginious.info.ucl.ac.be/course/LSINF1252/printf + +#. L'an dernier, vous avez écrit un programme permettant de détecter si une chaîne de caractères était un palindrome. Faites de même en C avec l'exercice INGINIOUS https://inginious.info.ucl.ac.be/course/LSINF1252/palindrome + +#. Ecrivez le corps de la fonction `swap2 <https://inginious.info.ucl.ac.be/course/LSINF1252/swap2>`_ permettant d'échanger les valeurs stockées dans deux variables de type entier. Faites de même lorsque les arguments de cette fonction sont des structures contenant des fractions : https://inginious.info.ucl.ac.be/admin/LSINF1252/task/swap + +#. La libraire `string(3)`_ implémente un grand nombre de fonctions de manipulation des strings qui vous serons utile lors de différents projets de programmation. + + * `strlen(3)`_ + * `strcat(3)`_ + * `strcasecmp(3)`_ + + + Ecrivez le code implémentant ces trois fonctions. Pour cela, créez un fichier ``string.c`` contenant la définition des fonctions et un fichier ``string.h`` avec les `déclarations <http://en.wikipedia.org/wiki/Declaration_(computer_programming)>`_ des fonctions. Vous devez aussi fournir un Makefile (cfr :ref:`outils:make`) qui permet de recompiler facilement votre programme en tapant ``make``. Pensez à implémenter quelques tests pour vos fonctions dans la fonction ``main`` et n'incluez pas l'exécutable dans l'archive. Pour la réalisation de ces tests, utilisez une librairie de tests unitaires telle que `CUnit <http://cunit.sourceforge.net>`_ + + Lorsque vous considérez que votre programme est correct, testez son bon fonctionnement via l'exercice correspondant sur inginious : https://inginious.info.ucl.ac.be/course/LSINF1252/mini-projet-string + +#. Faites l'exercice `swap <https://inginious.info.ucl.ac.be/course/LSINF1252/swap>`_ sur INGInious + +#. Faites les exercices de manipulation de bits sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252>`_. Pour réaliser ces exercices, réfléchissez d'abord sur papier, par exemple sur des blocs de 4 ou 8 bits. Pour la plupart des questions, il faut combiner des décalages à gauche ou à droite avec des opérations ``AND`` (``&``), ``OR`` (``|``) et ``NOT`` (``~``) bit à bit. + + - https://inginious.info.ucl.ac.be/course/LSINF1252/bits_leftmost + - https://inginious.info.ucl.ac.be/course/LSINF1252/bits_rightmost + - https://inginious.info.ucl.ac.be/course/LSINF1252/set_bit + - https://inginious.info.ucl.ac.be/course/LSINF1252/bits_spin + - https://inginious.info.ucl.ac.be/course/LSINF1252/bits_sum + - https://inginious.info.ucl.ac.be/course/LSINF1252/bits_strong + + +Questions de discussion +----------------------- + +.. only:: staff + + #. La zone mémoire utilisée diffère d'un type primitif à un autre. Ecrivez un code qui permet d'afficher le nombre de bytes utilisés sur un système 64 bits (une machine des salles) et une machine 32 bits (sirius, voir section :ref:`outils:ssh`) pour représenter un ``int``, ``long``, ``void *``, ``char *``, ``size_t`` et ``uint64_t``. Expliquez les différences. .. important:: Il est nécessaire de recompiler le code source si vous voulez exécuter le binaire sur une autre architecture. Le type ``uint64_t`` est défini dans `stdint.h`_. - Sur sirius ``gcc`` n'est pas forcément disponible, il faut dans ce cas utiliser ``cc`` à la place. + Sur sirius ``gcc`` n'est pas forcément disponible, il faut dans ce cas utiliser ``cc`` à la place -#. En utilisant des opérations binaires (décalage, and, or, ...), définissez un algorithme efficace pour trouver la valeur du bit le moins significatif d'un entier ``i`` (ex, 8 pour 56, 16 pour 208). +.. only:: staff - .. only:: staff + #. En utilisant des opérations binaires (décalage, and, or, ...), définissez un algorithme efficace pour trouver la valeur du bit le moins significatif d'un entier ``i`` (ex, 8 pour 56, 16 pour 208). .. note:: @@ -36,9 +71,6 @@ #. Soit ``char *ptr = "Test"``. Itérez sur ce pointeur et affichez avec `printf(3)`_ la valeur et l'adresse mémoire où se trouve stocké chaque caractère de deux façons différentes. Regardez la manpage de `printf(3)`_ pour savoir comment afficher la valeur d'un pointeur. - -#. Faites l'exercice sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/swap>`_ - #. La structure suivante ``foo_t`` est définie de façon à ce qu'elle contienne un ``char`` suivi d'un entier. D'après vous combien de bytes occupe cette structure en mémoire ? Vérifiez ce que vous pensiez en utilisant ``sizeof``. (bonus: expliquez vos résultats.) .. code-block:: c @@ -49,18 +81,6 @@ }; -#. La libraire `string(3)`_ implémente un grand nombre de fonctions de manipulation des strings qui vous serons utile lors de différents projets de programmation. - - * `strlen(3)`_ - * `strcat(3)`_ - * `strcasecmp(3)`_ - - - Ecrivez le code implémentant ces trois fonctions. Vous devrez créer un fichier ``string.c`` contenant la définition des fonctions et un fichier ``string.h`` avec les `déclarations <http://en.wikipedia.org/wiki/Declaration_(computer_programming)>`_ des fonctions. Vous devez aussi fournir un Makefile (cfr :ref:`outils:make`) qui permet de recompiler facilement votre programme en tapant ``make``. Pensez à implémenter quelques tests pour vos fonctions dans la fonction ``main`` et n'incluez pas l'exécutable dans l'archive. Pour la réalisation de ces tests, utilisez une librairie de tests unitaires telle que `CUnit <http://cunit.sourceforge.net>`_ - - Lorsque vous considérez que votre programme est correct, testez son bon fonctionnement via l'exercice correspondant sur inginious : https://inginious.info.ucl.ac.be/course/LSINF1252/mini-projet-string - - #. Lorsque l'on veut améliorer les performances d'un programme, il est utile de pouvoir mesurer précisément son temps d'exécution. La commande `time(1posix)`_ permet d'effectuer cette mesure depuis la ligne de commande. Parfois, on souhaite mesurer le temps de calcul une partie critique d'un code. Une façon simple pour obtenir cette mesure est d'utiliser `gettimeofday(2)`_ comme dans l'exemple ci-dessous (:download:`/Programmes/s2_perf.c`). .. literalinclude:: /Programmes/s2_perf.c diff --git a/Exercices/Programmes/prog-3.rst b/Exercices/Programmes/prog-3.rst index 50f11e8db839555f14a62b0cd99b5f3b6c00dc8c..90ec44815efec915143a920ef399e5126054ff81 100644 --- a/Exercices/Programmes/prog-3.rst +++ b/Exercices/Programmes/prog-3.rst @@ -2,39 +2,33 @@ .. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal .. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ +Questions INGINIOUS +------------------- -Questions ---------- +#. Le premier exercice INGINIOUS porte sur le heap et le stack : https://inginious.info.ucl.ac.be/course/LSINF1252/stack_vs_heap -#. Expliquez la différence entre `malloc(3)`_ et `calloc(3)`_. D'après vous, quel appel sera le plus lent ? +#. `malloc(3)`_ est une fonction clé en C puisqu'elle permet d'allouer une zone de mémoire. Elle a l'inconvénient de ne *pas* initialiser cette mémoire, contrairement à `calloc(3)`_. Lisez les pages de manuel de ces deux fonctions et implémentez vous-même la fonction `calloc(3)`_ en utilisant `malloc(3)`_ : https://inginious.info.ucl.ac.be/course/LSINF1252/calloc2 -#. Dans la fonction ``push`` du programme de manipulation d'un pile :download:`/../Theorie/C/S3-src/stack.c`, faut-il remplacer l'appel à `malloc(3)`_ par un appel à `calloc(3)`_ +#. Lorsque l'on utilise les fonctions de la librairie ou les appels systèmes, il est *nécessaire* de vérifier chaque fois leur valeur de retour pour éviter tout problème. Dans cet exercice, vous écrivez une variante de `malloc(3)`_ qui essaye plusieurs fois d'allouer de la mémoire pour pallier à un problème temporaire de manque de mémoire : https://inginious.info.ucl.ac.be/course/LSINF1252/sleep_malloc - .. only:: staff - - .. note:: - - Non. La zone mémoire est initialisée directement après. - -#. Le prototype de la fonction ``push`` du programme de manipulation d'une pile :download:`/../Theorie/C/S3-src/stack.c`, est ``void push(struct fraction_t *)``. Serait-il possible d'écrire une function push ayant comme prototype ``void push(struct fraction_t)`` ? Qu'est-ce qui changerait dans ce cas ? +#. La question suivante porte sur les déclarations de types de données (faites seulement les 7 premières sous-questions) : https://inginious.info.ucl.ac.be/course/LSINF1252/types - .. only:: staff +#. `strcpy(3)`_ est une fonction de la librairie standard qui permet de copier une chaîne de caractères. Cet exercice vous propose d'écrire une variante de cette fonction : https://inginious.info.ucl.ac.be/course/LSINF1252/strcpy - .. note:: +#. Lorsque l'on travaille avec les pointeurs, il est possible d'accéder à n'importe quel endroit de la mémoire. Cet exercice vous permet de tester vos compétences de manipulation des pointeurs: https://inginious.info.ucl.ac.be/course/LSINF1252/pointer_types - Pas possible. +#. Un exercice classique pour montrer que l'on comprend bien les pointeurs est de manipuler des listes chainées: https://inginious.info.ucl.ac.be/course/LSINF1252/basic_linked_list -#. Les fonctions ``push`` et ``pop`` définies dans l'exemple de manipulation d'une pile :download:`/../Theorie/C/S3-src/stack.c` utilisent une pile qui est définie par un pointeur qui est une variable globale. Est-il possible de réécrire ces fonctions de façon à ce qu'elles prennent comme argument un pointeur vers la pile ? Leurs prototypes deviendraient : +#. Un exercice sur le parcours simple d'un arbre binaire de recherche https://inginious.info.ucl.ac.be/course/LSINF1252/BST - - ``void push(struct node_t *, struct fraction_t *);`` - - ``struct fraction_t * pop(struct node_t *);`` +#. Un exercice où vous devez analyser l'information reçue d'un modem : https://inginious.info.ucl.ac.be/course/LSINF1252/modem_read - .. only:: staff +#. Maintenant que vous avez écrit de nombreuses fonctions sur INGINIOUS, il est temps pour vous d'écrire votre premier programme directement en C. Utilisez un éditeur de texte pour écrire le fichier ``test.c`` qui implémente un sous-ensemble du programme standard `test(1)`_. Pensez à structurer votre code en utilisant des sous-fonctions. Compilez votre programme sur votre ordinateur avant de le soumettre sur INGINIOUS. https://inginious.info.ucl.ac.be/course/LSINF1252/commandetest - .. note:: - Oui, idéalement dans ce cas, il faudrait définir une fonction init qui renverrait un ``struct node_t *``. +Questions complémentaires +------------------------- #. En C, on peut définir des tableaux à deux dimensions avec une déclaration comme ``int a[3][3];``. Ecrivez un petit programme qui utilise des pointeurs pour déterminer si un tel tableau à deux dimensions est stocké ligne par ligne ou colonne par colonne. @@ -55,10 +49,93 @@ Questions printf("WTF!!!\n"); } +#. Exécutez plusieurs fois le code suivant. Expliquez les différents résultats obtenus. + .. code-block:: c + + int global; + void main(void) + { + int local; + int *ptr1 = (int *)malloc(sizeof(*ptr1)); + int *ptr2 = (int *)malloc(sizeof(*ptr2)); -#. Considérons la structure suivante: + printf("global %p loc %p p1 %p p2 %p\n", &global, &local, ptr1, ptr2); + } - .. code-block:: c + .. only:: staff + + .. note:: + + L'adresse de ``global`` ne change pas, car elle fait partie du segment texte du programme. Les autres sont soit sur la pile (stack), ou sur le tas (heap). + +#. Un étudiant a fait l'implémentation d'un sous-ensemble des fonctions définies dans string.h, mais il rencontre quelques problèmes avec son code :download:`/Programmes/src/string.c`. Utilisez `gdb <http://sites.uclouvain.be/SystInfo/notes/Outils/html/gdb.html>`_ pour corriger son code. Utilisez le flag ``-g`` de ``gcc`` pour ajouter les informations de debug dans votre executable. Pour rappel, voici quelques commandes importantes de `gdb <http://sites.uclouvain.be/SystInfo/notes/Outils/html/gdb.html>`_: + + - ``run [ARGS]`` permet de lancer l'execution du programme avec les arguments ARGS si spécifiés. + - ``break string.c:9`` met un point d'arrêt à la ligne 9 du fichier string.c + - ``next`` permet d'executer la ligne courante et de s'arrêter à la ligne suivante + - ``print var`` affiche la valeur de la variable ``var`` + - ``backtrace`` affiche la pile d'appel des fonctions courantes + - ``quit`` quitte `gdb <http://sites.uclouvain.be/SystInfo/notes/Outils/html/gdb.html>`_ + + .. only:: staff + + .. note:: + + 4 erreurs: strlen ne check pas NULL, strlen appelé à chaque itération de strcat, argc pas vérifié, concat_2 pas initialisé + + +#. Vous travaillez sur un programme qui doit manipuler des vecteurs. Afin de pouvoir supporter des vecteurs de taille quelconque, vous décidez de réimplémenter ces vecteurs vous même en utilisant des pointeurs. Votre programme définit la structure ``struct vector_t`` et les fonctions ci-dessous. +Implémentez ces fonctions sans jamais utiliser la notation des tableaux en C (``[`` et ``]``). + + .. literalinclude:: /Programmes/src/vector.c + :encoding: utf-8 + :language: c + :start-after: ///AAA + :end-before: ///BBB + + +.. only:: staff + + #. Faites l'exercice relatif aux `linked lists <https://inginious.info.ucl.ac.be/course/LSINF1252/linked_lists_1>`_ sur INGInious. + + +.. only:: staff + + #. Expliquez la différence entre `malloc(3)`_ et `calloc(3)`_. D'après vous, quel appel sera le plus lent ? + +.. only:: staff + + #. Dans la fonction ``push`` du programme de manipulation d'un pile :download:`/../Theorie/C/S3-src/stack.c`, faut-il remplacer l'appel à `malloc(3)`_ par un appel à `calloc(3)`_ + + .. note:: + + Non. La zone mémoire est initialisée directement après. + +.. only:: staff + + #. Le prototype de la fonction ``push`` du programme de manipulation d'une pile :download:`/../Theorie/C/S3-src/stack.c`, est ``void push(struct fraction_t *)``. Serait-il possible d'écrire une function push ayant comme prototype ``void push(struct fraction_t)`` ? Qu'est-ce qui changerait dans ce cas ? + + .. note:: + + Pas possible. + +.. only:: staff + + #. Les fonctions ``push`` et ``pop`` définies dans l'exemple de manipulation d'une pile :download:`/../Theorie/C/S3-src/stack.c` utilisent une pile qui est définie par un pointeur qui est une variable globale. Est-il possible de réécrire ces fonctions de façon à ce qu'elles prennent comme argument un pointeur vers la pile ? Leurs prototypes deviendraient : + + - ``void push(struct node_t *, struct fraction_t *);`` + - ``struct fraction_t * pop(struct node_t *);`` + + .. note:: + + Oui, idéalement dans ce cas, il faudrait définir une fonction init qui renverrait un ``struct node_t *``. + +.. only:: staff + + + #. Considérons la structure suivante: + + .. code-block:: c typedef struct { char c; @@ -67,17 +144,14 @@ Questions } test_t; - Combien de bytes seront utilisés en mémoire pour représenter cette structure? Représentez graphiquement la position en mémoire de chaque élément (utilisez `printf(3)`_ et ``%p``), observez-vous des trous ? Expliquez. + Combien de bytes seront utilisés en mémoire pour représenter cette structure? Représentez graphiquement la position en mémoire de chaque élément (utilisez `printf(3)`_ et ``%p``), observez-vous des trous ? Expliquez. Serait-il possible d'utiliser moins de bytes pour représenter cette structure ? Si oui, comment ? - - .. only:: staff - .. note:: La structure prend 16 bytes d'espace (sur une machine 64-bits - 12 bytes sur une machine 32 bits). C'est dû au fait que les champs sont alignés à des multiples de 64 bits (resp. 32 bits) pour éviter d'avoir des parties de variables copié sur plusieurs registres. Pour optimiser, il suffit de reordonner les champs. Par exemple: - .. code-block:: c + .. code-block:: c typedef struct { char c; @@ -85,20 +159,28 @@ Questions long l; } test_t; +.. only:: staff + + .. note:: + + Elle bypasse l'alignement décrit dans la question précédente. L'avantage est que la structure prend l'espace minimale n'importe soit l'ordonnancement des champs. Le désavatage est que la CPU doît faire plus de travail pour lire la variable, car des parties de la variable sont sur plusieurs registres, et donc la CPU doît faire des bit-shifts. + + + + #. Expliquez à quoi sert l'attribut ``packed`` des structures dans `gcc(1)`_ (regardez la manpage). Appliquez cet attribut à la structure de l'exercice précédent. Qu'observez-vous comme différence ? Quel sont les avantages et désavantages d'utiliser cet attribut ? Dans quel cas est-il intéressant de l'utiliser ? - .. only:: staff .. note:: - Elle bypasse l'alignement décrit dans la question précédente. L'avantage est que la structure prend l'espace minimale n'importe soit l'ordonnancement des champs. Le désavatage est que la CPU doît faire plus de travail pour lire la variable, car des parties de la variable sont sur plusieurs registres, et donc la CPU doît faire des bit-shifts. + Il bypasse l'alignement décrit dans la question précédente. L'avantage est que la structure prend l'espace minimal n'importe soit l'ordonnancement des champs. Le désavantage est que la CPU doît faire plus de travail pour lire la variable, car des parties de la variable sont sur plusieurs registres, et donc la CPU doît faire des bit-shifts. #. Exécutez plusieurs fois le code suivant. Expliquez les différents résultats obtenus. .. code-block:: c int global; - int main(void) + -int main (int argc, char** argv) { int local; int *ptr1 = (int *)malloc(sizeof(*ptr1)); @@ -107,20 +189,3 @@ Questions printf("global %p loc %p p1 %p p2 %p\n", &global, &local, ptr1, ptr2); return EXIT_SUCCESS; } - - .. only:: staff - - .. note:: - - L'adresse de ``global`` ne change pas, car elle fait partie du segment texte du programme. Les autres sont soit sur la pile (stack), ou sur le tas (heap). - -#. Faites l'exercice sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/linked_lists_1>`_ - -#. Vous travaillez sur un programme qui doit manipuler des vecteurs. Afin de pouvoir supporter des vecteurs de taille quelconque, vous décidez de réimplémenter ces vecteurs vous même en utilisant des pointeurs. Votre programme définit la structure ``struct vector_t`` et les fonctions ci-dessous. -Implémentez ces fonctions sans jamais utiliser la notation des tableaux en C (``[`` et ``]``). - - .. literalinclude:: /Programmes/src/vector.c - :encoding: utf-8 - :language: c - :start-after: ///AAA - :end-before: ///BBB diff --git a/Exercices/Programmes/prog-4-asm.rst b/Exercices/Programmes/prog-4-asm.rst new file mode 100644 index 0000000000000000000000000000000000000000..b41356b38b87be80473cad456696b6a1285423dd --- /dev/null +++ b/Exercices/Programmes/prog-4-asm.rst @@ -0,0 +1,93 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + +Exercices +========= + +#. Dans le cours théorique, nous avons parlé des instructions ``set`` qui permettent de fixer la valeur d'un byte d'un registre en fonction de la valeur des drapeaux du registre ``eflags``. Comment feriez-vous pour compiler en assembleur la ligne ``b=(a>0)`` sans utilisez cette instruction et en sachant que les valeurs de ``a`` et ``b`` sont initialement dans les registres ``%eax`` et ``%ecx``. Pour répondre à cette question, écrivez d'abord un code en C semblable au code ci-dessous : + + .. code-block:: c + + if ( condition) + { b=1; } + else + { b=0; } + + +#. Avec le compilateur gcc, il est aussi possible de compiler du code assembleur directement dans une programme C. Cette fonctionnalité est intéressante si vous voulez tester de petites fonctions écrites en langage assembleur. Ainsi, une fonction baptisée ``rien`` et qui ne fait absolument rien peut s'écrire comme suit: + + + .. code-block:: c + + extern void rien(); // indique au compilateur que la fonction est externe + + __asm__( + "rien:\n" + " ret\n" + ); + + + En utilisant l'assembleur [IA32]_, écrivez les instructions assembleur qui permettent d'implémenter une fonction qui ne prend aucun argument et retourne toujours l'entier ``1``. + + .. only:: staff + + .. note:: + + .. code-block:: c + + movl $1,%eax + ret + + + De la même façon, écrivez la fonction ``add`` qui prend deux arguments de type ``int`` et retourne la somme de ces deux arguments. + + .. only:: staff + + .. note:: + + .. code-block:: c + + /* add(int a, int b) */ + __asm__( + "add:\n" + " subl $8, %esp\n" + " movl 16(%esp), %eax\n" + " movl 12(%esp), %ebx\n" + " movl %ebx, %eax\n" + " addl $8, %esp\n" + " ret\n" + ); + +#. Considérons une fraction de la mémoire représentée dans le tableau ci-dessous. + + ========== ======== + Adresse Valeur + ========== ======== + 0x0C 0x00 + 0x08 0xFF + 0x04 0x02 + 0x00 0x01 + ========== ======== + + Si ``%esp`` contient initialement la valeur ``0x0C`` et que ``%eax`` et ``%ebx`` contiennent respectivement ``0x02`` et ``0x03``, que deviennent cette mémoire et les registres durant l'exécution de : + + .. code-block:: nasm + + pushl %eax + pushl %ebx + popl %ecx + +#. En C, il n'est pas rare de voir dans certains programmes que la valeur de retour de certaines fonctions est ignorée. C'est une mauvaise pratique qui peut donner lieu à pas mal de problèmes. Connaissant la façon dont la valeur de retour d'une fonction ``int f()`` est gérée en assembleur, expliquez ce qu'il se passe en pratique lorsque la valeur de retour de ``f`` n'est pas sauvegardée. + + .. only:: staff + + .. note:: + + La valeur de retour étant dans %eax, il n'y a aucun problème à l'ignorer, elle sera juste écrasée à la première utilisation de %eax + + + + +#. Vous trouverez sur INGInious plusieurs exemples de questions typiques sur l'assembleur à l'examen. Ces questions portent sur la traduction d'un code assembleur dans son équivalent en C. `Première question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm1>`_, `deuxième question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm2>`_, `troisième question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm3>`_ et `quatrième question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm4>`_ . + diff --git a/Exercices/Programmes/prog-4.rst b/Exercices/Programmes/prog-4.rst index a74dc1900a852a0504a48024075a5a46c8ce9bc2..7df939f744afbacf7ce1e9b11450c052a8991734 100644 --- a/Exercices/Programmes/prog-4.rst +++ b/Exercices/Programmes/prog-4.rst @@ -2,6 +2,46 @@ .. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal .. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ +Exercices INGINIOUS +=================== + +Deux sortes d'exercices INGINIOUS vous sont proposés durant cette semaine. Les premiers portent sur les structures chaînées car ces structures de données permettent de bien vérifier la compréhension des pointeurs en C. + + - https://inginious.info.ucl.ac.be/course/LSINF1252/simple_stack + - https://inginious.info.ucl.ac.be/course/LSINF1252/cmp_func + - https://inginious.info.ucl.ac.be/course/LSINF1252/linked_structs + - https://inginious.info.ucl.ac.be/course/LSINF1252/advanced_queue + - https://inginious.info.ucl.ac.be/course/LSINF1252/order_relation_linked_list + +Après avoir écrit de nombreuses fonctions C, il est maintenant temps pour vous de commencer à écrire des +programmes composés de plusieurs fonctions. Pour cela, l'utilitaire `make(1)`_ vous sera très utile. Prenez un peu de temps pour lire le chapitre qui lui est consacré dans le syllabus et essayez de répondre aux questions ci-dessous : + + - https://inginious.info.ucl.ac.be/course/LSINF1252/s2_make + - https://inginious.info.ucl.ac.be/course/LSINF1252/s2_make_calc + - https://inginious.info.ucl.ac.be/course/LSINF1252/s2_make_mcq + +.. only:: staff + + - https://inginious.info.ucl.ac.be/course/LSINF1252/s3_make + - https://inginious.info.ucl.ac.be/course/LSINF1252/s3_make_mcq + - https://inginious.info.ucl.ac.be/course/LSINF1252/s3_cunit_basics + - https://inginious.info.ucl.ac.be/course/LSINF1252/s3_make_tests + +Lorsque l'on écrit des programmes en C ou dans un autre langage, il est important de tester +le bon fonctionnement de toutes les fonctions du programme pour éviter des erreurs et autres +bugs difficiles à corriger. L'idéal est de commencer par écrire les tests qui valident le bon +fonctionnement de chaque fonction *avant* d'écrire cette fonction. Plusieurs librairies peuvent vous +aider à écrire de tels tests. CUnit (:ref:`outils:ref_cunit`) est l'un d'entre elles. +Prenez le temps de lire le chapitre +qui lui est consacré dans le syllabus. + +Pour démontrer votre bon utilisation de `make(1)`_ et CUnit, reprenez le programme que vous +avez écrit pour l'exercice `test <https://inginious.info.ucl.ac.be/course/LSINF1252/commandetest>`_ +, +divisez-le en plusieurs fichiers, ajoutez-y des tests unitaires pour chaque fonction et +utilisez `make(1)`_ pour automatiser le tout. Si vous voulez allez plus loin, essayez d'utiliser +la librarie `getopt(3)`_ pour traiter les arguments reçus en ligne de commande. + Exercices ========= @@ -25,7 +65,9 @@ Exercices :start-after: ///AAA :end-before: ///BBB -#. Dans le cours théorique, nous avons parlé des instructions ``set`` qui permettent de fixer la valeur d'un byte d'un registre en fonction de la valeur des drapeaux du registre ``eflags``. Comment feriez-vous pour compiler en assembleur la ligne ``b=(a>0)`` sans utilisez cette instruction et en sachant que les valeurs de ``a`` et ``b`` sont initialement dans les registres ``%eax`` et ``%ecx``. Pour répondre à cette question, écrivez d'abord un code en C semblable au code ci-dessous : +.. only:: staff + + #. Dans le cours théorique, nous avons parlé des instructions ``set`` qui permettent de fixer la valeur d'un byte d'un registre en fonction de la valeur des drapeaux du registre ``eflags``. Comment feriez-vous pour compiler en assembleur la ligne ``b=(a>0)`` sans utilisez cette instruction et en sachant que les valeurs de ``a`` et ``b`` sont initialement dans les registres ``%eax`` et ``%ecx``. Pour répondre à cette question, écrivez d'abord un code en C semblable au code ci-dessous : .. code-block:: c @@ -35,9 +77,20 @@ Exercices { b=0; } -#. En utilisant l'assembleur [IA32]_, écrivez les instructions assembleur qui permettent d'implémenter une fonction qui ne prend aucun argument et retourne toujours l'entier ``1``. + #. Avec le compilateur gcc, il est aussi possible de compiler du code assembleur directement dans une programme C. Cette fonctionnalité est intéressante si vous voulez tester de petites fonctions écrites en langage assembleur. Ainsi, une fonction baptisée ``rien`` et qui ne fait absolument rien peut s'écrire comme suit: + + + .. code-block:: c - .. only:: staff + extern void rien(); // indique au compilateur que la fonction est externe + + __asm__( + "rien:\n" + " ret\n" + ); + + + En utilisant l'assembleur [IA32]_, écrivez les instructions assembleur qui permettent d'implémenter une fonction qui ne prend aucun argument et retourne toujours l'entier ``1``. .. note:: @@ -46,7 +99,26 @@ Exercices movl $1,%eax ret -#. Considérons une fraction de la mémoire représentée dans le tableau ci-dessous. + + De la même façon, écrivez la fonction ``add`` qui prend deux arguments de type ``int`` et retourne la somme de ces deux arguments. + + .. note:: + + .. code-block:: c + + /* add(int a, int b) */ + __asm__( + "add:\n" + " subl $8, %esp\n" + " movl 16(%esp), %eax\n" + " movl 12(%esp), %ebx\n" + " movl %ebx, %eax\n" + " addl $8, %esp\n" + " ret\n" + ); + + + #. Considérons une fraction de la mémoire représentée dans le tableau ci-dessous. ========== ======== Adresse Valeur @@ -65,9 +137,7 @@ Exercices pushl %ebx popl %ecx -#. En C, il n'est pas rare de voir dans certains programmes que la valeur de retour de certaines fonctions est ignorée. C'est une mauvaise pratique qui peut donner lieu à pas mal de problèmes. Connaissant la façon dont la valeur de retour d'une fonction ``int f()`` est gérée en assembleur, expliquez ce qu'il se passe en pratique lorsque la valeur de retour de ``f`` n'est pas sauvegardée. - - .. only:: staff + #. En C, il n'est pas rare de voir dans certains programmes que la valeur de retour de certaines fonctions est ignorée. C'est une mauvaise pratique qui peut donner lieu à pas mal de problèmes. Connaissant la façon dont la valeur de retour d'une fonction ``int f()`` est gérée en assembleur, expliquez ce qu'il se passe en pratique lorsque la valeur de retour de ``f`` n'est pas sauvegardée. .. note:: @@ -75,4 +145,7 @@ Exercices -#. Trois exercices se trouvent sur INGInious. Un exercice sur la `Comparaison de Fractions <https://inginious.info.ucl.ac.be/course/LSINF1252/fractions>`_, un nouvel exercice sur les `les chaînées <https://inginious.info.ucl.ac.be/course/LSINF1252/linked_lists_2>`_ et finalement l'implémentation de `strsep <https://inginious.info.ucl.ac.be/course/LSINF1252/strsep>`_. + #. Trois exercices se trouvent sur INGInious. Un exercice sur la `Comparaison de Fractions <https://inginious.info.ucl.ac.be/course/LSINF1252/fractions>`_, un nouvel exercice sur les `les listes chaînées <https://inginious.info.ucl.ac.be/course/LSINF1252/linked_lists_2>`_ et finalement l'implémentation de `strsep <https://inginious.info.ucl.ac.be/course/LSINF1252/strsep>`_. + + #. Vous trouverez également sur INGInious plusieurs exemples de questions typiques sur l'assembleur à l'examen. Ces questions portent sur la traduction d'un code assembleur dans son équivalent en C. `Première question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm1>`_, `deuxième question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm2>`_, `troisième question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm3>`_ et `quatrième question <https://inginious.info.ucl.ac.be/course/LSINF1252/asm4>`_ . + diff --git a/Exercices/Programmes/prog-5.rst b/Exercices/Programmes/prog-5.rst index 4937a07ed7f8e068aa7d2e04cf704cc3e05c601b..4a54d83ad8fa75b5ea4220d5ac78c974479b6e00 100644 --- a/Exercices/Programmes/prog-5.rst +++ b/Exercices/Programmes/prog-5.rst @@ -2,74 +2,120 @@ .. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal .. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ +Exercices INGINIOUS +------------------- + +Les exercices INGINIOUS de cette semaine ont comme objectif de vous familiariser avec +les appels systèmes `open(2)`_, `close(2)`_, `read(2)`_, `write(2)`_ et `stat(2)`_ qui +permettent de manipuler les fichiers contenant des données binaires. + +1. Le `premier exercice <https://inginious.info.ucl.ac.be/course/LSINF1252/s5_file_exists>`_ est +une mise en jambe. En utilisant `open(2)`_ (et `close(2)`_), pouvez-vous vérifier si un +fichier dont le nom est passé en argument existe ? + +2. L'avantage des fichiers binaires est qu'il est possible de sauvegarder directement un tableau stocké en mémoire dans le fichier en utilisant `write(2)`_ pour écrire chaque élément du tableau dans un fichier. En lisant les pages de manuel de `write(2)`_, vous verrez même qu'un seul appel à `write(2)`_ peut suffire à sauver tout un tableau dans un fichier. Ecrivez cette `fonction save <https://inginious.info.ucl.ac.be/course/LSINF1252/s4_file_save_struct>`_. + +3. Un fichier binaire peut être utilisé pour stocker tous les éléments d'un tableau d'entiers. Ecrivez la `fonction sum_file <https://inginious.info.ucl.ac.be/course/LSINF1252/s4_read_file_array_integer>`_ qui prend comme argument un nom de fichier contenant un tel tableau et calcule la somme de tous les entiers stockés dans le fichier. Pensez aux cas d'erreurs possibles si le fichier n'a pas la bonne taille. + +4. Vous continuez à explorer les fichiers binaires qui permettent de stocker tous les éléments d'un tableau d'entiers. Cette fois-ci vous devez écrire une `première fonction <https://inginious.info.ucl.ac.be/course/LSINF1252/s5_big_array_get_set>`_ pour récupérer la valeur d'un +élément du tableau stocké dans le fichier et une `seconde fonction <https://inginious.info.ucl.ac.be/course/LSINF1252/s5_big_array_get_set>`_ pour modifier la valeur d'un élément de ce tableau. + +5. En ligne de commande, `cp(1)`_ vous permet de copier complètement un fichier quel que soit son contenu. Pouvez-vous implémenter l'équivalent de cette commande dans la `fonction copy <https://inginious.info.ucl.ac.be/course/LSINF1252/s5_file_copy>`_ que vous allez écrire en C. + + Exercices -========= +--------- + + +1. Consultez la page de manuel de `chmod(1)`_ ou d'autres sources pour déterminer la signification des bits de permissions lorsqu'ils sont associés à un répertoire. Expliquez notamment à quoi sert le bit d'exécution sur un répertoire. + + .. only:: staff + + le bit x permet d'autoriser le parcours du répertoire + +2. Quelles sont les permissions associées à votre répertoire de login ? Ces permissions permettent-elles à d'autres étudiants d'accéder à vos fichiers ? Si oui, utilisez `chmod(1)`_ pour supprimer cette autorisation de lecture par défaut dans votre répertoire. + +3. Comment feriez-vous en utilisant `chmod(1)`_ pour créer un répertoire dans lequel vous pouvez lire et écrire, tout étudiant peut lire mais aucun membre du staff (à part l'administrateur système bien entendu) ne peut lire ? + + .. only:: staff + + il faut que l'étudiant soit dans le même groupe et que le répertoire soit accessible au groupe, au minimum 00750 + +4. Le répertoire ``/tmp`` est particulier car il est destiné à pouvoir contenir des fichiers de n'importe quel utilisateur. Pouvez-vous expliquer les permissions utilisées pour ce répertoire ? + + .. only:: staff + + pas besoin de parler du sticky bit sauf si les étudiants l'abordent + +.. only:: staff + + 5. La commande `lsof(8)`_ permet de lister les fichiers ouverts par un processus. A votre avis, comment cette commande fonctionne-t-elle ? + + L'OS maintient une table de tous les fichiers ouverts avec leur inode. Cette table est accessible via /proc + + 6. Lorsqu'un exécutable est lancé avec `execve(2)`_, il hérite des descripteurs de fichiers qui étaient ouverts dans le processus qui a exécuté `execve(2)`_. Comment feriez-vous en utilisant uniquement l'appel système `open(2)`_ pour déterminer combien de descripteurs de fichiers étaient ouverts au démarrage de votre programme ? + + Il suffit de regarder quelle est la valeur de retour de open. Si open retourne 3, cela indique que seuls stdin, stdout et stderr étaient ouverts + +5. Est-il possible dans un processus d'exécuter ``int fd1=open("f",O_RDWR);`` et juste après ``int fd2=open("f",O_RDONLY);`` ? Si oui, quelles seront les valeurs des descripteurs de fichiers retournés lors des appels système. Si non, quelles seront les valeurs de ``errno``? + + .. only:: staff + + Oui, c'est possible. Dans ce cas, les offset pointers sont différents pour les deux copies du même fichier. Il est utile de faire un dessin pour que les étudiants visualisent bien la situation + +.. only:: staff + + 8. Dans un shell, on exécute la commande ``/bin/echo "1234" > /test.txt``. Quels sont les appels systèmes effectués par le shell avant l'exécution de ``/bin/echo`` ? -#. La fonction `pthread_join(3)`_ utilise un deuxième argument de type ``void **``. Pourquoi est-il nécessaire d'utiliser un pointeur vers un pointeur et pas simplement un pointeur ``void *`` ? -#. A votre avis, pourquoi le premier argument de la fonction `pthread_create(3)`_ est-il un pointeur de type `pthread_t *` alors que le premier argument de la fonction `pthread_join(3)`_ est lui simplement de type `pthread_t`? + fork, fermer stdout, ouvrir test.txt - par défaut il aura le premier fd libre, c-a-d celui de stdout qui vient d'être fermé et ensuite exécution avec execve -#. Avec les threads POSIX, comment peut-on passer plusieurs arguments à la fonction démarrée par `pthread_create(3)`_ ? Ecrivez un petit exemple en C qui permet de passer un entier et un caractère à cette fonction. + 9. Dans un shell, on exécute la commande ``./a.out < in.txt > out.txt``. Quelles sont les appels systèmes qui doivent être exécutés par le shell pour lancer cet exécutable comme demandé par l'utilisateur ? -#. Ecrivez un code qui permet de récupérer un tableau d'entiers d'un thread. Exercice disponible sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/threads_1>`_. -#. Essayez de lancer un grand nombre de threads d'exécution sur votre machine. Quel est le nombre maximum de threads que `pthread_create(3)`_ vous autorise à lancer ? + fork puis dans le fils + close(stdin) + open(in.txt,O_RDONLY) + close(stdout) + open(out.txt,O_WRONLY) + execve (qui préserver les descripteurs ouverts) -#. Quelle différence voyez-vous entre `pthread_exit(3)`_ et `exit(3)`_ ? + 10. Dans un shell, on exécute la commande ``cat < in.txt | grep sinf1252``. Quelles sont les appels systèmes qui doivent être exécutés par le shell pour lancer cette commande comme demandé par l'utilisateur ? -#. Un étudiant souhaite passer un tableau d'entiers comme argument à un thread et écrit le code suivant. Qu'en pensez-vous ? + deux forks + premier fils + close(stdin) + close(stdout) - .. literalinclude:: /Programmes/src/pthread-array.c - :encoding: utf-8 - :language: c - :start-after: ///AAA + 11. Dans un shel `bash(1)`_, lorsque l'on suffixe une commande avec ``2>&1``, le shell redirige la sortie d'erreur standard vers la sortie standard. Quels sont les appels systèmes utilisés par le shell pour réussir cette redirection ? -#. Considérons le programme de test des threads POSIX ci-dessous. Ce programme utilise 4 threads qui incrémentent chacun un million de fois une variable globale. + le shell va faire fork pour exécuter le programme, mais avant il doit fermer stdout et le dupliquer avec dup ou dup2 - .. literalinclude:: /Programmes/src/pthread-test.c - :encoding: utf-8 - :language: c - :start-after: ///AAA - Exécutez ce programme (:download:`/Programmes/src/pthread-test.c`) et observez le résultat qu'il affiche à l'écran. Pouvez-vous expliquer le comportement de ce programme ? +6. Comment se comporte l'appel système `write(2)`_ lorsque le disque sur lequel on souhaite écrire des données est plein ? Peut-on distinguer cette erreur d'un problème d'écriture sur le disque ? -#. Résolvez des sudokus. Exercice disponible sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/sudoku>`_. + .. only:: staff -Mini-projet: Mesure de performance -================================== + il retourne une erreur et met errno à ENOSPC -On vous demande de transformer un code monothreadé en un code multithreadé. Vous devez vous baser sur le code présent dans l'archive: :download:`/Programmes/src/prog-5-measure/prog-5-measure.tar.gz`. Le programme permet de chiffrer ou déchiffrer des mots de passe passés en argument au programme. Ce dernier prend plusieurs arguments additionels: +7. A quoi sert l'appel système `sync(2)`_ ? - * ``-p`` définit le mot de passe à utiliser - * ``-n`` définit le nombre de fois que chaque mot de passe est chiffré/déchiffré - * ``-d`` définit que le programme doit déchiffrer les mots de passes (il chiffre par défaut) + .. only:: staff -Un exemple d'utilisation du programme est le suivant: + A forcer l'écriture des données sur le disque - .. code-block:: c +8. Le programme :download:`/Programmes/src/writeperf.c` permet de tester les performances des écritures dans write sur un système de fichiers. Compilez-le et exécutez le avec différents tailles de buffers passés à `write(2)`_. Mesurez le temps d'exécution avec la commande `time(1posix)`_ et comparez le temps qu'il faut pour écrire 100MB en blocs de 1 MB ou en blocs de 1 KB. Faites de même en activant la synchronisation avec le paramètre ``-s``. - $ ./crypt -p toto -n 10000 test Bonjour! - CAC7EF483F90C988 0F5766990DFA0914 - $ ./crypt -p toto -n 10000 -d CAC7EF483F90C988 0F5766990DFA0914 - test Bonjour! + .. only:: staff -Vous devez donc vous baser sur le code existant afin de paralléliser le chiffrement/déchiffrement des mots de passe. Vous ne devez pas nécessairement afficher les mots de passe (ou chiffrés) dans l'ordre. Vous devez cependant ajouter un argument ``-t`` au programme qui définit le nombre de threads que le programme exécutera en parallèle. + Les performances décroissent car il y a plus d'appels systèmes qui sont effectués. sync force l'écriture et bypasse le buffer. Il est utile de mentionner l'existence de ce buffer -On vous demande également d'évaluer l'impact des arguments ``-t`` et ``-n`` sur l'exécution du programme. Pensez à exécuter votre programme avec un argument ``-n`` suffisamment grand si vous voulez évaluer l'impact de ``-t``. On vous demande plus spécifiquement de générer un graphique qui montre pour différentes valeurs le temps de calcul. Vous pouvez utiliser `time(1posix)`_ afin de récupérer le temps d'exécution d'un programme: +.. only:: staff - .. code-block:: c + 15. Effectuez l'exercice sur la manipulation de fichiers sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/fichiers>`_. - $ time ./crypt -p toto -n 10000 -d CAC7EF483F90C988 0F5766990DFA0914 - test Bonjour! +.. 17. `tee(1)`_ est un utilitaire qui permet de recopier son entrée standard vers un ou plusieurs fichiers et également vers sa sortie standard. Il peut être utile pour par exemple inspecter des données échangées entre deux processus à travers un :term:`pipe`. Quels sont les appels systèmes exécutés par `tee(1)`_ lors de l'exécution de la commande ``cat /tmp/t | tee /tmp/tee.out | grep "sinf1252" `` - real 0m0.019s - user 0m0.016s - sys 0m0.000s - $ time ./crypt -p toto -n 9999999 -d 774069EB86ED86FA 7D1AC0A4CF56F942 - test Bonjour! - real 0m16.104s - user 0m16.101s - sys 0m0.000s diff --git a/Exercices/Programmes/prog-6.rst b/Exercices/Programmes/prog-6.rst index ef9ebe6f2327076d9b44e769e7b2edfe6bdcdfab..56fa13a237beb1eefdf901241474539c59bfad0c 100644 --- a/Exercices/Programmes/prog-6.rst +++ b/Exercices/Programmes/prog-6.rst @@ -6,120 +6,189 @@ Exercices ========= +#. La fonction `pthread_join(3)`_ utilise un deuxième argument de type ``void **``. Pourquoi est-il nécessaire d'utiliser un pointeur vers un pointeur et pas simplement un pointeur ``void *`` ? + +#. A votre avis, pourquoi le premier argument de la fonction `pthread_create(3)`_ est-il un pointeur de type `pthread_t *` alors que le premier argument de la fonction `pthread_join(3)`_ est lui simplement de type `pthread_t`? + +#. Avec les threads POSIX, comment peut-on passer plusieurs arguments à la fonction démarrée par `pthread_create(3)`_ ? Ecrivez un petit exemple en C qui permet de passer un entier et un caractère à cette fonction. + +.. only:: staff + + Ecrivez un code qui permet de récupérer un tableau d'entiers d'un thread. Exercice disponible sur `INGInious threads_1 <https://inginious.info.ucl.ac.be/course/LSINF1252-new/threads_1>`_. + +#. Essayez de lancer un grand nombre de threads d'exécution sur votre machine. Quel est le nombre maximum de threads que `pthread_create(3)`_ vous autorise à lancer ? + +#. Quelle différence voyez-vous entre `pthread_exit(3)`_ et `exit(3)`_ ? + +#. Un étudiant souhaite passer un tableau d'entiers comme argument à un thread et écrit le code suivant. Qu'en pensez-vous ? + + .. literalinclude:: /Programmes/src/pthread-array.c + :encoding: utf-8 + :language: c + :start-after: ///AAA + +#. Considérons le programme de test des threads POSIX ci-dessous. Ce programme utilise 4 threads qui incrémentent chacun un million de fois une variable globale. + + .. literalinclude:: /Programmes/src/pthread-test.c + :encoding: utf-8 + :language: c + :start-after: ///AAA + + Exécutez ce programme (:download:`/Programmes/src/pthread-test.c`) et observez le résultat qu'il affiche à l'écran. Pouvez-vous expliquer le comportement de ce programme ? + +#. Lorsque l'on travaille avec des threads, il est important de bien se rappeler dans quelle zone de la mémoire les différents types d'information sont stockés dans un programme C. Le programme ci-dessous fournit quelques exemples de : + + * variable globale statique + * variable globale + * variable déclarée dans la fonction ``main`` et dont le pointeur est un des arguments aux threads + * variable statique déclarée à l'intérieur d'une fonction + * variable locale déclarée dans une fonction + + + .. code-block:: c + + #include <pthread.h> + #include <stdio.h> + #include <stdlib.h> + + #define N_THREADS 3 + + struct thread_args { + int *ptr; + int thread_num; + }; + + pthread_mutex_t mutex; + + static int global_static = 1; + int global_int = 11; + + static void *thread_work(void *ptr) + { + struct thread_args *arg = (struct thread_args *)ptr; + int thr_num = arg->thread_num; + + static int static_val = 111; + int local_val = 222; + int *main_val = arg->ptr; + + pthread_mutex_lock(&mutex); + + printf("thread no %d, global_static is %d\n", thr_num, global_static); + fflush(stdout); + global_static++; + + printf("thread no %d, global_int is %d\n", thr_num, global_int); + fflush(stdout); + global_int++; + + printf("thread no %d, static_val is %d\n", thr_num, static_val); + fflush(stdout); + static_val++; + + printf("thread no %d, local_val is %d\n", thr_num, local_val); + fflush(stdout); + local_val++; + + printf("thread no %d, main_val is %d\n", thr_num, *main_val); + fflush(stdout); + (*main_val)++; + + pthread_mutex_unlock(&mutex); + + pthread_exit(NULL); + } + + int main (int argc, char const *argv[]) + { + int i; + int val = 22; + struct thread_args args[N_THREADS]; + pthread_t threads[N_THREADS]; + + pthread_mutex_init(&mutex, NULL); + + for (i = 0; i < N_THREADS; ++i) { + args[i].ptr = &val; + args[i].thread_num = i; + pthread_create(&threads[i], NULL, thread_work, (void *)&args[i]); + } + + for (i = 0; i < N_THREADS; ++i) + pthread_join(threads[i], NULL); + + return 0; + } -#. Ecrivez un petit programme qui vous permet de montrer quelles variables sont accessibles à différents threads. Les variables à montrer sont: - - * variable globale statique - * variable globale - * variable déclarée dans la fonction ``main`` et dont le pointeur est un des arguments aux threads - * variable statique déclarée à l'intérieur d'une fonction - * variable locale déclarée dans une fonction - - .. only:: staff - - .. note:: - - .. code-block:: c - - // note : fflush n'a pas encore été vu, ne pas en parler - #include <pthread.h> - #include <stdio.h> - #include <stdlib.h> - - #define N_THREADS 3 - - struct thread_args { - int *ptr; - int thread_num; - }; - - pthread_mutex_t mutex; +#. D'après vous (essayez d'expérimenter), que se passe-t-il si: - static int global_static = 1; - int global_int = 11; + * un thread exécute deux fois `pthread_mutex_lock(3posix)`_ sur le même mutex d'affilée ? + * un thread exécute deux fois d'affilée `pthread_mutex_unlock(3posix)`_ - static void *thread_work(void *ptr) - { - struct thread_args *arg = (struct thread_args *)ptr; - int thr_num = arg->thread_num; - static int static_val = 111; - int local_val = 222; - int *main_val = arg->ptr; +#. Dans la partie théorie, nous avons vu comment s'assurer qu'un seul thread peut accéder à une zone critique à la fois. On vous propose deux solutions (dont une déjà vue dans la partie théorie): - pthread_mutex_lock(&mutex); + .. code-block:: c - printf("thread no %d, global_static is %d\n", thr_num, global_static); - fflush(stdout); - global_static++; + pthread_mutex_lock(&mutex_global); + global=increment(global); + pthread_mutex_unlock(&mutex_global); - printf("thread no %d, global_int is %d\n", thr_num, global_int); - fflush(stdout); - global_int++; + et - printf("thread no %d, static_val is %d\n", thr_num, static_val); - fflush(stdout); - static_val++; + .. code-block:: c - printf("thread no %d, local_val is %d\n", thr_num, local_val); - fflush(stdout); - local_val++; + while (pthread_mutex_trylock(&mutex_global)) ; + global=increment(global); + pthread_mutex_unlock(&mutex_global); - printf("thread no %d, main_val is %d\n", thr_num, *main_val); - fflush(stdout); - (*main_val)++; + Discuter les avantages et inconvénients des ces deux solutions. (Regardez la man page de `pthread_mutex_trylock(3posix)`_) - pthread_mutex_unlock(&mutex); +#. L'outil ``helgrind`` (décrit dans la section :ref:`outils:helgrind-ref`) permet de trouver des deadlocks ou autres problèmes. Exécutez-le sur le petit programme suivant :download:`/Programmes/src/pthread-philo.c` et analysez ce qu'il affiche. - pthread_exit(NULL); - } - int main (int argc, char const *argv[]) - { - int i; - int val = 22; - struct thread_args args[N_THREADS]; - pthread_t threads[N_THREADS]; - pthread_mutex_init(&mutex, NULL); +.. only:: staff - for (i = 0; i < N_THREADS; ++i) { - args[i].ptr = &val; - args[i].thread_num = i; - pthread_create(&threads[i], NULL, thread_work, (void *)&args[i]); - } + Résolvez des sudokus. Exercice disponible sur `INGInious sudoku <https://inginious.info.ucl.ac.be/course/LSINF1252-new/sudoku>`_. - for (i = 0; i < N_THREADS; ++i) - pthread_join(threads[i], NULL); +Mini-projet: Mesure de performance +================================== - return 0; - } +On vous demande de transformer un code monothreadé en un code multithreadé. Vous devez vous baser sur le code présent dans l'archive: :download:`/Programmes/src/prog-5-measure/prog-5-measure.tar.gz`. Le programme permet de chiffrer ou déchiffrer des mots de passe passés en argument au programme. Ce dernier prend plusieurs arguments additionels: -#. D'après vous (essayez d'expérimenter), que se passe-t-il si: + * ``-p`` définit le mot de passe à utiliser + * ``-n`` définit le nombre de fois que chaque mot de passe est chiffré/déchiffré + * ``-d`` définit que le programme doit déchiffrer les mots de passes (il chiffre par défaut) - * un thread exécute deux fois `pthread_mutex_lock(3posix)`_ sur le même mutex d'affilée ? - * un thread exécute deux fois d'affilée `pthread_mutex_unlock(3posix)`_ +Un exemple d'utilisation du programme est le suivant: + .. code-block:: console -#. Dans la partie théorie, nous avons vu comment s'assurer qu'un seul thread peut accéder à une zone critique à la fois. On vous propose deux solutions (dont une déjà vue dans la partie théorie): + $ ./crypt -p toto -n 10000 test Bonjour! + CAC7EF483F90C988 0F5766990DFA0914 + $ ./crypt -p toto -n 10000 -d CAC7EF483F90C988 0F5766990DFA0914 + test Bonjour! - .. code-block:: c +Vous devez donc vous baser sur le code existant afin de paralléliser le chiffrement/déchiffrement des mots de passe. Vous ne devez pas nécessairement afficher les mots de passe (ou chiffrés) dans l'ordre. Vous devez cependant ajouter un argument ``-t`` au programme qui définit le nombre de threads que le programme exécutera en parallèle. - pthread_mutex_lock(&mutex_global); - global=increment(global); - pthread_mutex_unlock(&mutex_global); +On vous demande également d'évaluer l'impact des arguments ``-t`` et ``-n`` sur l'exécution du programme. Pensez à exécuter votre programme avec un argument ``-n`` suffisamment grand si vous voulez évaluer l'impact de ``-t``. On vous demande plus spécifiquement de générer un graphique qui montre pour différentes valeurs le temps de calcul. Vous pouvez utiliser `time(1posix)`_ afin de récupérer le temps d'exécution d'un programme: - et + .. code-block:: console - .. code-block:: c + $ time ./crypt -p toto -n 10000 -d CAC7EF483F90C988 0F5766990DFA0914 + test Bonjour! - while (pthread_mutex_trylock(&mutex_global)) ; - global=increment(global); - pthread_mutex_unlock(&mutex_global); + real 0m0.019s + user 0m0.016s + sys 0m0.000s + $ time ./crypt -p toto -n 9999999 -d 774069EB86ED86FA 7D1AC0A4CF56F942 + test Bonjour! - Discuter les avantages et inconvénients des ces deux solutions. (Regardez la man page de `pthread_mutex_trylock(3posix)`_) + real 0m16.104s + user 0m16.101s + sys 0m0.000s -#. L'outil ``helgrind`` (décrit dans la section :ref:`theorie:helgrind-ref`) permet de trouver des deadlocks ou autres problèmes. Exécutez-le sur le petit programme suivant :download:`/Programmes/src/pthread-philo.c` et analysez ce qu'il affiche. .. exemple et tutoriel intéressant diff --git a/Exercices/Programmes/prog-7.rst b/Exercices/Programmes/prog-7.rst index ff67a7bee07aa25bfbe83cfaf223f9f91bfd61b9..adcdfdec23f4b9b0ace15ded4bfdec31d8800422 100644 --- a/Exercices/Programmes/prog-7.rst +++ b/Exercices/Programmes/prog-7.rst @@ -110,4 +110,11 @@ Exercices #. Les mutex et les sémaphores peuvent être utilisés pour résoudre des problèmes d'exclusion mutuelle. Le programme :download:`/QCM/S7/src/pthread-mutex-perf.c` utilise des mutex. Modifiez-le pour utiliser des sémaphores à la place et comparez le coût en termes de performance entre les mutex et les sémaphores. -#. Faites l'exercice sur les producteurs/consommateurs sur `INGInious <https://inginious.info.ucl.ac.be/course/LSINF1252/producteur-consommateur>`_. +#. Faites l'exercice sur les `producteurs/consommateurs <https://inginious.info.ucl.ac.be/course/LSINF1252/PC>`_ sur `INGInious <https://inginious.info.ucl.ac.be>`_. + +Outils +====== + +#. Si vous ne l'aviez pas fait durant la troisième semaine, prenez le temps pour faire l'exercice relatif à `gdb(1)`_ . Le debugger pourra vous être très utile pour le projet. + +#. Un autre outil particulièrement intéressant est :ref:`outils:valgrind-ref` qui permet de détecter différents problèmes d'allocation de la mémoire. Prenez le temps nécessaire pour comprendre comment ce logiciel fonctionne, cette compétence vous fera gagner du temps plus tard et vous évitera de perdre du temps pour corriger un problème d'allocation de mémoire difficile à détecter. \ No newline at end of file diff --git a/Exercices/Programmes/prog-9.rst b/Exercices/Programmes/prog-9.rst.old similarity index 100% rename from Exercices/Programmes/prog-9.rst rename to Exercices/Programmes/prog-9.rst.old diff --git a/Exercices/Programmes/src/prog2.c b/Exercices/Programmes/src/prog2.c new file mode 100644 index 0000000000000000000000000000000000000000..bc13550745334df8a12c66e30ed7474657da664b --- /dev/null +++ b/Exercices/Programmes/src/prog2.c @@ -0,0 +1,156 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +struct fraction { + int num; + int den; +}; + + +struct fraction * simp1(struct fraction f); +struct fraction * simp2(struct fraction * f); +struct fraction simp3(struct fraction f) { + struct fraction f2= {.num=1, .den=2}; + return f2; +} + + +int main(int argc, char **argv){ + double d; + double tab[4]={1,2,3,4}; + double mat[3][4]={ {1,2,3,4},{5,6,7,8},{9,10,11,12}} ; + double *ptr1; + double *ptrl; + double *ptr2; + + ptr1=tab; + + printf("sizeof(d)=%d\n",sizeof(d)); + printf("&d=%p\n",&d); + for(int i=0;i<4;i++){ + printf("tab[%d]=%f at address %p\n",i,tab[i],&(tab[i]) ); + printf("tab[%d]=%f at address %p\n",i,*(ptr1+i),ptr1+i); + printf("tab[%d]=%f at address %p\n",i,*ptr1+i,ptr1+i); + printf("tab[%d]=%f at address %p\n",i,(*(ptr1))+(double)i,ptr1+i); + } + + ptr2=&(mat[0][0]); + + for(int i=0;i<3;i++){ + for(int j=0;j<4;j++) { + printf("mat[%d][%d]=%f at address %p\n",i,j,mat[i][j],&(mat[i][j])); + printf("mat[%d][%d]=%f at relative address %d\n",i,j,mat[i][j],&(mat[i][j])-&(mat[0][0])); + printf("mat[%d][%d]=%f at address %p\n",i,j,*(ptr2+i*4+j),ptr2+i*4+j); + } + } + + int l=1; + ptrl=mat[1]; + for(int c=0;c<4;c++){ + printf("mat[%d][%d]=%f at address %p\n",l,c,mat[l][c],&(mat[l][c])); + printf("mat[%d][%d]=%f at address %p\n",l,c,*(ptrl+c),ptrl+c); + } + + + struct record { + char c[3]; + double num; + char d; + int data[4]; + }; + + struct record t1; + t1.c[0]='A'; + t1.c[1]='B'; + t1.c[2]='C'; + t1.num=42.0; + t1.d='Z'; + t1.data[1]=2; + printf("sizeof(test)=%d\n",sizeof(t1)); + printf("&(t1)=%p\n",&(t1)); + printf("&(t1.c[0])=%p\n",&(t1.c[0])); + printf("&(t1.num)=%p\n",&(t1.num)); + printf("&(t1.d)=%p\n",&(t1.d)); + printf("&(t1.data)=%p\n",&(t1.data)); + + char *dp=(char *) &(t1) + 4 + 8; + printf("%p\n",dp); + + + + struct fraction f1; + f1.num=1; + f1.den=17; + + printf("sizeof(fraction)=%d\n",sizeof(f1)); + printf("&(f1)=%p\n",&(f1)); + printf("&(f1.num)=%p\n",&(f1.num)); + printf("&(f1.num)+1=%p\n",&(f1.num)+1); + printf("&(f1.den)=%p\n",&(f1.den)); + + struct fraction f2; + f2=simp3(f1); + printf("%d/%d\n",f2.num,f2.den); + + struct fraction tabfract[2]; + tabfract[0].num=1; + tabfract[0].den=7; + tabfract[1].num=2; + tabfract[1].den=3; + + struct fraction *p=tabfract; + printf("%d \n",(p+1)->den); + printf("&(tabfract[0])=%p\n",&(tabfract[0])); + printf("&(tabfract)=%p\n",&(tabfract)); + printf("tabfract=%p\n",tabfract); + + printf("&(tabfract[1])=%p\n",&(tabfract[1])); + + printf("argc=%d\n",argc); + for(int i=0;i<argc;i++) { + char *ptr=*(argv+i); + printf("argv[%d]=%s\n",i,ptr); + for(int j=0;j<strlen(ptr);j++) { + printf("%c is at %p\n",*(ptr+j),ptr+j); + } + } + + char *string="abcdef"; + char string2[]="abcdef"; + /* + char string3="ab"; + char *string4='A'; + char string5='B'; + char *string6="C"; + */ + printf("%s\n",string); + printf("%s\n",string2); + + + printf("%s\n",string+2); + + + printf("%c\n",*(string+3)); + + printf("%c\n",*(string+6)); + printf("test\n"); + + string2[0]='A'; + *(string2)='A'; + *(string2+5)='F'; + *(string2+strlen(string2))='G'; + *(string2+strlen(string2)+1)='H'; + + printf("%s\n",string2); + + // see https://stackoverflow.com/questions/1335786/c-differences-between-char-pointer-and-array + + // string++; + // printf("%s\n",string); + + + + + +} diff --git a/Exercices/Programmes/src/string.c b/Exercices/Programmes/src/string.c new file mode 100644 index 0000000000000000000000000000000000000000..0190db7f20704ba25d9f5f1dd317dc78660d3cc3 --- /dev/null +++ b/Exercices/Programmes/src/string.c @@ -0,0 +1,60 @@ +#include <stdlib.h> +#include <stdio.h> + +/** + * Returns the number of characters in s + */ +size_t strlen(const char *s) +{ + int i = 0; + while(s[i] != '\0') + { + i++; + } + return i; +} + +/** + * Appends the src string to the dest string, overwriting + * the null byte ('\0') at the end of dest, and then adds + * a terminating null byte. The strings may not overlap, + * and the dest string must have enough space for the result. + */ +char * strcat(char *s1, const char *s2) +{ + int i; + for(i = 0; i < strlen(s2); i++) + { + *(s1 + strlen(s1) + i) = *(s2 + i); + } + *(s1 + strlen(s1) + i) = '\0'; + return s1; +} + +int main(int argc, char *argv[]) { + /* Test function */ + char *text_1 = "Hello"; + char *text_2 = " World!"; + char *text_3 = NULL; + char concat_1[100]; + char concat_2[100]; + int i; + + printf("Length of %s: %lu\n", text_1, strlen(text_1)); + printf("Length of %s: %lu\n", text_2, strlen(text_2)); + printf("Length of %s: %lu\n", text_3, strlen(text_3)); + + for (i = 0; i < strlen(text_1); i++) + concat_1[i] = *(text_1 + i); + printf("Putting %s and %s together gives %s\n", text_1, text_2, strcat(concat_1, text_2)); + + /* Taking arguments, if any */ + printf("Length of %s: %lu\n", argv[1], strlen(argv[1])); + printf("Length of %s: %lu\n", argv[2], strlen(argv[2])); + + for (i = 0; i < strlen(argv[1]); i++) + concat_1[i] = *(argv[1] + i); + printf("Putting %s and %s together gives %s\n", argv[1], argv[2], strcat(concat_2, argv[2])); + + return 0; +} diff --git a/Exercices/Projets/P1/projet-1.rst b/Exercices/Projets/P1/projet-1.rst.old similarity index 100% rename from Exercices/Projets/P1/projet-1.rst rename to Exercices/Projets/P1/projet-1.rst.old diff --git a/Exercices/Projets/P1/projet-1.tar.gz b/Exercices/Projets/P1/projet-1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7763a9feaddd0740e57ff41a5c5f4916ea8e2b3e Binary files /dev/null and b/Exercices/Projets/P1/projet-1.tar.gz differ diff --git a/Exercices/Projets/P2/enonce.rst b/Exercices/Projets/P2/enonce.rst.old similarity index 100% rename from Exercices/Projets/P2/enonce.rst rename to Exercices/Projets/P2/enonce.rst.old diff --git a/Exercices/Projets/P2/projet-2.tar.gz b/Exercices/Projets/P2/projet-2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..f4621e13a9489f90e025ca30ffb17b805766dd78 Binary files /dev/null and b/Exercices/Projets/P2/projet-2.tar.gz differ diff --git a/Exercices/Projets/P3/enonce.rst b/Exercices/Projets/P3/enonce.rst.old similarity index 100% rename from Exercices/Projets/P3/enonce.rst rename to Exercices/Projets/P3/enonce.rst.old diff --git a/Exercices/QCM/S11/qcm-11.rst b/Exercices/QCM/S11/qcm-11.rst index 1305b81314d2f74a172cac247fd94f8cd797c6bd..86ca74c92e69b5dbd0c9d21c7db7fce7244199a1 100644 --- a/Exercices/QCM/S11/qcm-11.rst +++ b/Exercices/QCM/S11/qcm-11.rst @@ -84,7 +84,7 @@ Parmi les affirmations suivantes relatives au bit de validité utilisé dans la .. class:: negative -- il y a un seule bit de validité pour une table des pages +- il y a un seul bit de validité pour une table des pages .. class:: comment diff --git a/Exercices/QCM/S2/qcm-2.rst b/Exercices/QCM/S2/qcm-2.rst index c501f05d33f9adf534e87df8bf704ae7e8499b0c..d7de148864e733fa49c09d9b8e3fc1459e58fdc9 100644 --- a/Exercices/QCM/S2/qcm-2.rst +++ b/Exercices/QCM/S2/qcm-2.rst @@ -15,7 +15,7 @@ Semaine 2 : Types de données ============================ -La matière couverte cette semaine la section relative aux `types de données <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/datatypes.html>`_ (jusque et y compris la section relative aux `expressions de manipulation de bits <http://sinf1252.info.ucl.ac.be/Theorie/C/datatypes/#les-expressions-de-manipulation-de-bits>`_ +La matière couverte cette semaine la section relative aux `types de données <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/datatypes.html>`_ (jusque et y compris la section relative aux `expressions de manipulation de bits <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/datatypes.html#les-expressions-de-manipulation-de-bits>`_ Question 1. Conversion de types diff --git a/Exercices/QCM/S3/qcm-3.rst b/Exercices/QCM/S3/qcm-3.rst index ef87e05e6b0f673872704c72e1da4d6688590433..42b20c0a535877a30d03f3493747ce006ccf3506 100644 --- a/Exercices/QCM/S3/qcm-3.rst +++ b/Exercices/QCM/S3/qcm-3.rst @@ -183,7 +183,7 @@ Considérons le fragment de programme ci-dessous. } -Lors de l'exécution de ce programmes, les valeurs des différentes variables sont stockées en mémoire. Un seul des groupes d'affirmations ci-dessous est correct. Lequel ? +Lors de l'exécution de ce programme, les valeurs des différentes variables sont stockées en mémoire. Un seul des groupes d'affirmations ci-dessous est correct. Lequel ? .. class:: positive diff --git a/Exercices/QCM/S9/qcm-9.rst b/Exercices/QCM/S9/qcm-9.rst index d2d1eb4c481b4531f897f118aa999dbbd5d74595..1bc476b57b7886e83f7dcf584977d04bd4a9cfa6 100644 --- a/Exercices/QCM/S9/qcm-9.rst +++ b/Exercices/QCM/S9/qcm-9.rst @@ -21,7 +21,7 @@ La matière couverte cette semaine porte sur le système de fichiers et sa manip Question 1. Accès aux fichiers ------------------------------ -Les bits de permissions permet de contrôler l'accès aux fichiers. Considérons le répertoire ci-dessous : +Les bits de permissions permettent de contrôler l'accès aux fichiers. Considérons le répertoire ci-dessous : .. code-block:: console @@ -481,7 +481,7 @@ Après exécution de ces commandes, un seul des groupes d'affirmations suivant e .. class:: negative - - - les fichiers ``a`` et ``c`` ont des `inode` différents + - les fichiers ``a`` et ``c`` ont des `inodes` différents - les fichiers ``e`` et ``d`` ont la même taille - l'`inode` correspondant au fichier ``d`` indique qu'il y a trois liens vers lui diff --git a/Exercices/QCM/qcm.rst b/Exercices/QCM/qcm.rst.old similarity index 92% rename from Exercices/QCM/qcm.rst rename to Exercices/QCM/qcm.rst.old index 2bbe3e43f6a231e2728b22b058397297aae6f315..102313cdb3ce756dc5ffbd9c41d6a79162e8c5d1 100644 --- a/Exercices/QCM/qcm.rst +++ b/Exercices/QCM/qcm.rst.old @@ -43,6 +43,3 @@ Parmi les groupes d'affirmations ci-dessous, un seul ne contient que des affirma -.. include:: ../../../links.rst -.. include:: ../../../man_links.rst -.. include:: ../../../incl_links.rst diff --git a/Exercices/_static b/Exercices/_static new file mode 120000 index 0000000000000000000000000000000000000000..7a2b653646f86d98f976df94c66c017b5d24ecbe --- /dev/null +++ b/Exercices/_static @@ -0,0 +1 @@ +../_static \ No newline at end of file diff --git a/Exercices/benchmark.rst b/Exercices/benchmark.rst deleted file mode 100644 index b16ba573a49ed36d2e77bfed9b902c2d2868dd7a..0000000000000000000000000000000000000000 --- a/Exercices/benchmark.rst +++ /dev/null @@ -1,39 +0,0 @@ - - -Evaluation des performances des appels systèmes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Pour le troisième projet, vous devrez choisir un appel système, analyser la façon dont il doit être utilisé, sur base de sa page de manuel et de livres de référence et ensuite en évaluer ses performances. Pour cette évaluation de performances, vous devrez modifier le programme de benchmark développé par Benoît Legat, Nicolas Demol et Maxime Houtain : - - https://github.com/blegat/benchmark.git - -Pour s'exécuter, ce programme nécessite une version récente de `gnuplot <http://www.gnuplot.info>`_ , un programme permettant d'afficher des données de façon graphique. Téléchargez les sources de ce programme et installez-le en faisant : - -.. code:: console - - - wget http://sourceforge.net/projects/gnuplot/files/gnuplot/4.6.5/gnuplot-4.6.5.tar.gz - tar xzvf gnuplot-4.6.5.tar.gz - cd gnuplot-4.6.5 - ./configure - make - -Le programme gnuplot est maintenant compilé et prêt à être utilisé. Le programme exécutable est dans le répertoire gnuplot-4.6.5/src/gnuplot - -Chargez le programme de benchmark et compilez-le comme suit : - -.. code:: console - - git clone https://github.com/blegat/benchmark.git - cd benchmark - PATH=~/src/gnuplot-4.6.5/src:${PATH} ./bootstrap.sh - make - -La troisième commande permet de forcer l'utilisation de la version récente de gnuplot que vous avez installé à la place de la version par défaut du système qui n'est pas supportée par l'outil de benchmark. Une fois le benchmark compilé, vous pouvez l'exécuter et tester les benchmarks fournis. Commencez par ceux qui se trouvent dans les répertoires suivants : - - - ``tab`` - - ``thread`` - - ``amdahl`` - - ``types`` - -Pour exécuter un benchmark, lancez simplement ``make show`` dans le répertoire du benchmark. Il exécutera alors le benchmark et produira un fichier HTML contenant les résultats obtenus ainsi que des fichiers au format .csv avec les valeurs mesurées. Essayez d'interpréter les résultats obtenus. Pouvez-vous justifier l'évolution des performances que vous observez ? diff --git a/Exercices/benchmark.rst.old b/Exercices/benchmark.rst.old new file mode 100644 index 0000000000000000000000000000000000000000..762a91db09f535c4a1fbeeca1a291d0131926587 --- /dev/null +++ b/Exercices/benchmark.rst.old @@ -0,0 +1,39 @@ +.. -*- coding: utf-8 -*- + +Evaluation des performances des appels systèmes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Pour le troisième projet, vous devrez choisir un appel système, analyser la façon dont il doit être utilisé, sur base de sa page de manuel et de livres de référence et ensuite en évaluer ses performances. Pour cette évaluation de performances, vous devrez modifier le programme de benchmark développé par Benoît Legat, Nicolas Demol et Maxime Houtain : + + https://github.com/blegat/benchmark.git + +Pour s'exécuter, ce programme nécessite une version récente de `gnuplot <http://www.gnuplot.info>`_ , un programme permettant d'afficher des données de façon graphique. Téléchargez les sources de ce programme et installez-le en faisant : + +.. code:: console + + + wget http://sourceforge.net/projects/gnuplot/files/gnuplot/4.6.5/gnuplot-4.6.5.tar.gz + tar xzvf gnuplot-4.6.5.tar.gz + cd gnuplot-4.6.5 + ./configure + make + +Le programme gnuplot est maintenant compilé et prêt à être utilisé. Le programme exécutable est dans le répertoire gnuplot-4.6.5/src/gnuplot + +Chargez le programme de benchmark et compilez-le comme suit : + +.. code:: console + + git clone https://github.com/blegat/benchmark.git + cd benchmark + PATH=~/src/gnuplot-4.6.5/src:${PATH} ./bootstrap.sh + make + +La troisième commande permet de forcer l'utilisation de la version récente de gnuplot que vous avez installé à la place de la version par défaut du système qui n'est pas supportée par l'outil de benchmark. Une fois le benchmark compilé, vous pouvez l'exécuter et tester les benchmarks fournis. Commencez par ceux qui se trouvent dans les répertoires suivants : + + - ``tab`` + - ``thread`` + - ``amdahl`` + - ``types`` + +Pour exécuter un benchmark, lancez simplement ``make show`` dans le répertoire du benchmark. Il exécutera alors le benchmark et produira un fichier HTML contenant les résultats obtenus ainsi que des fichiers au format .csv avec les valeurs mesurées. Essayez d'interpréter les résultats obtenus. Pouvez-vous justifier l'évolution des performances que vous observez ? diff --git a/Exercices/bib.rst b/Exercices/bib.rst new file mode 100644 index 0000000000000000000000000000000000000000..97c0a1ecffdddba2bf2e35d116e34cfebec76ae5 --- /dev/null +++ b/Exercices/bib.rst @@ -0,0 +1,15 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + +************* +Bibliographie +************* + + +.. [Downey2008] Downey, A., `The Little Book of Semaphores`, Second Edition, Green Tea Press, 2008, + +.. [IA32] intel, `Intel® 64 and IA-32 Architectures : Software Developer’s Manual`, Combined Volumes: 1, 2A, 2B, 2C, 3A, 3B and 3C, December 2011, http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf + +.. [Kerrisk2010] Kerrisk, M., `The Linux Programming Interface`, No Starch Press, 2010, http://my.safaribooksonline.com/book/programming/linux/9781593272203 + diff --git a/Exercices/conf.py b/Exercices/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..75f693559c306b19894e1e6f08b8d135e0d8c85c --- /dev/null +++ b/Exercices/conf.py @@ -0,0 +1,320 @@ +# -*- coding: utf-8 -*- +# +# SINF1252 documentation build configuration file, created by +# sphinx-quickstart on Tue Jan 3 16:17:09 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' +sys.path.append(os.path.abspath('mcq')) +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.mathjax', 'sphinx.ext.intersphinx','mcq' ] + + +# mcq + +mcq_nb_prop=3 +mcq_upload_url='http://inginious.info.ucl.ac.be' +mcq_inginious_url='http://inginious.info.ucl.ac.be/cnp3' + +# ucomment +#sys.path.append(os.path.abspath(os.getcwd())) +#extensions.append('ucomment-extension') +#html_translator_class = 'ucomment-extension.ucomment_html_translator' + +# Point to your Django application, which contains all +# the other settings required. +#ucomment = {} +#ucomment['django_application_path'] = '/home/cpaasch/sinf1252/ucommentsite/ucommentapp' + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' +#source_encoding = 'latin1' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'SINF1252 : Exercices ' +copyright = u'2012-2014, O. Bonaventure, G. Detal, C. Paasch' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2014' +# The full version, including alpha/beta/rc tags. +release = '2014' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = 'fr' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build', '.#*', '*/.#*', 'QCM/*' ] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +rst_epilog = """ +.. include:: /../Theorie/links.rst +.. include:: /../Theorie/man_links.rst +.. include:: /../Theorie/incl_links.rst +""" + +# Intersphinx +intersphinx_mapping = {'theorie': ('https://sites.uclouvain.be/SystInfo/notes/Theorie/html/', None), 'outils': ('https://sites.uclouvain.be/SystInfo/notes/Outils/html/', None), 'exercices': ('https://sites.uclouvain.be/SystInfo/notes/Exercices/html/', None)} + + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = u'Systèmes informatiques' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static', 'mcq/static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'SINF1252doc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +'papersize': 'a4paper', + +# The font size ('10pt', '11pt' or '12pt'). +'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'SINF1252.tex', u'SINF1252', + u'O. Bonaventure, G. Detal, C. Paasch', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'sinf1252', u'SINF1252', + [u'O. Bonaventure, G. Detal, C. Paasch'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'SINF1252', u'SINF1252', + u'O. Bonaventure, G. Detal, C. Paasch', 'SINF1252', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'SINF1252' +epub_author = u'O. Bonaventure, G. Detal, C. Paasch' +epub_publisher = u'O. Bonaventure, G. Detal, C. Paasch' +epub_copyright = u'2013, O. Bonaventure, G. Detal, C. Paasch' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +#try: +# open('.staff','r') +# tags.add('staff') +# print "Build as staff member" +#except: +# print "Build as student" diff --git a/Exercices/index.rst b/Exercices/index.rst index ca4d9764145fe074cd839ca772ba31548f9a528f..4b73b277c04f51a2495cddb5136aa7a2acc1939f 100644 --- a/Exercices/index.rst +++ b/Exercices/index.rst @@ -20,7 +20,7 @@ Exercices :maxdepth: 2 intro - + bib .. Projets/P1/projet-1 .. Projets/P2/enonce diff --git a/Exercices/intro.rst b/Exercices/intro.rst index e6a733338e0bfd5c72fdeab03e33404b33655068..e641d513d5404320cf1a1b582c11b89526d38b61 100644 --- a/Exercices/intro.rst +++ b/Exercices/intro.rst @@ -11,6 +11,8 @@ Cette section comprend deux types d'exercices afin de permettre aux étudiants d Première semaine ---------------- +La matière couverte cette semaine correspond à l'`introduction aux systèmes informatiques <https://sites.uclouvain.be/SystInfo/notes/Theorie/html/intro.html>`_ et au `langage C <https://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/intro-C.html>`_ . Le volet pratique est important et les sections relatives au `shell <https://sites.uclouvain.be/SystInfo/notes/Outils/html/shell.html>`_ et aux `processus <https://sites.uclouvain.be/SystInfo/notes/Outils/html/processus.html>`_ de la section dédiée aux `autres outils <https://sites.uclouvain.be/SystInfo/notes/Outils/html>`_ devraient vous être utiles. + .. toctree:: :maxdepth: 2 @@ -19,11 +21,10 @@ Première semaine Programmes/prog-1 - Deuxième semaine ---------------- -La matière couverte cette semaine correspond à la section relative aux `types de données <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/datatypes.html#les-expressions-de-manipulation-de-bits>`_ (jusque et y compris la section relative aux `expressions de manipulation de bits <http://sites.uclouvain.be/SystInfo/notes/Theorie/C/datatypes/#les-expressions-de-manipulation-de-bits>`_) +La matière couverte cette semaine correspond à la section relative aux `types de données <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/datatypes.html#les-expressions-de-manipulation-de-bits>`_ (jusque et y compris la section relative aux `expressions de manipulation de bits <http://sites.uclouvain.be/SystInfo/notes/Theorie/C/datatypes/#les-expressions-de-manipulation-de-bits>`_) .. toctree:: :maxdepth: 2 @@ -35,7 +36,7 @@ La matière couverte cette semaine correspond à la section relative aux `types Troisième semaine ----------------- -La matière couverte cette semaine correspond aux sections relative à l'`organisation de la mémoire <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/malloc.html#organisation-de-la-memoire>`_ +La matière couverte cette semaine correspond aux sections relative à l'`organisation de la mémoire <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/C/malloc.html#organisation-de-la-memoire>`_ Vous commencez à développer des programmes complets, le debugger `gdb <https://sites.uclouvain.be/SystInfo/notes/Outils/html/gdb.html>`_ pourrait vous aider. Il est décrit dans la section `gdb <https://sites.uclouvain.be/SystInfo/notes/Outils/html/gdb.html>`_ .. toctree:: :maxdepth: 2 @@ -47,10 +48,17 @@ La matière couverte cette semaine correspond aux sections relative à l'`organi Quatrième semaine ----------------- +Durant les dernières semaines, vous avez appris les bases de l'écriture de fonctions en C. L'objectif de cette semaine est de vous amener à être capable d'écrire des programmes comprenant plusieurs fonctions. La matière couverte cette semaine correspond aux sections : - - `Organisation des ordinateurs <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html>`_ - - `Etude de cas : IA32 <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html#etude-de-cas-architecture-ia32>`_ + - :ref:`theorie:ordinateurs` + - :ref:`theorie:complementsC` + +En outre, vous devrez aussi lire les sections de la partie Outils qui sont relatives à + +- :ref:`outils:make` +- :ref:`outils:ref_cunit` + .. toctree:: :maxdepth: 2 @@ -62,25 +70,29 @@ La matière couverte cette semaine correspond aux sections : Cinquième semaine ----------------- -La matière couverte cette semaine correspond aux sections : - - :ref:`theorie:complementsC` - - :ref:`theorie:threads` +La matière de cette semaine porte sur l'utilisation du système de fichiers et les ``pipe``. Elle est décrite dans les sections : + + - :ref:`theorie:utilisateurs` + - :ref:`theorie:fichiers` + - :ref:`theorie:pipe` .. toctree:: :maxdepth: 2 - mcq-ex/qcm-5 + mcq-ex/qcm-9 Programmes/prog-5 + Sixième semaine --------------- -La matière de cette semaine porte sur la communication entre les threads. Elle est décrite dans la section : +La matière couverte cette semaine correspond aux sections : - - :ref:`theorie:comthreads` + - :ref:`theorie:threads` (sauf la section `Utilisation d'instruction atomique`) + - :ref:`theorie:comthreads` (jusqu'à la section `Le problème des philosophes`) .. toctree:: :maxdepth: 2 @@ -89,14 +101,19 @@ La matière de cette semaine porte sur la communication entre les threads. Elle Programmes/prog-6 - Septième semaine ---------------- -La matière de cette semaine porte sur l'utilisation des sémaphores et quelques compléments sur les threads. Elle est décrite dans la section : +La matière de cette semaine porte sur l'utilisation des mutex et des sémaphores et quelques compléments sur les threads. Elle est décrite dans la section : + - :ref:`theorie:comthreads` (à partir de la section `Le problème des philosophes`) - :ref:`theorie:coordinationthreads` +En outre, vous devrez aussi lire les sections de la partie Outils qui sont relatives à + +- :ref:`outils:valgrind-ref` +- :ref:`outils:gdb-ref` + .. toctree:: :maxdepth: 2 @@ -121,26 +138,39 @@ La matière de cette semaine porte sur le fonctionnement des processus. Elle est Neuvième semaine ---------------- -La matière de cette semaine porte sur l'utilisation du système de fichiers et les ``pipe``. Elle est décrite dans les sections : +La matière de cette semaine porte sur les pipes, la mémoire virtuelle et les fichiers mappés en mémoire : - - :ref:`theorie:utilisateurs` - - :ref:`theorie:fichiers` - :ref:`theorie:pipe` + - :ref:`theorie:vmem` + - :ref:`theorie:fctvmem` + - :ref:`theorie:stockage` + - :ref:`theorie:remplacement` + - :ref:`theorie:mmap` + + +.. only:: html + + `QCM11 <http://sites.uclouvain.be/SystInfo/qcm/Mission-11-qcm.html>`_ + +Séance tutorée +^^^^^^^^^^^^^^ .. toctree:: :maxdepth: 2 - mcq-ex/qcm-9 - Programmes/prog-9 + Programmes/prog-11 Dixième semaine --------------- -La matière de cette semaine porte sur les signaux, les sémaphores nommés et le partage de fichiers : +La matière de cette semaine porte sur les utilisations avancées de la mémoire virtuelle, les sméaphores nommés et le partage de fichiers : - - :ref:`theorie:signaux` + - :ref:`theorie:shmem` + - :ref:`theorie:forkmem` + - :ref:`theorie:vmstat` + - :ref:`theorie:execvmem` - :ref:`theorie:semname` - :ref:`theorie:fileshare` @@ -150,25 +180,16 @@ Séance tutorée .. toctree:: :maxdepth: 2 - mcq-ex/qcm-10 - Programmes/prog-10 - + Programmes/prog-12 Onzième semaine --------------- -La matière de cette semaine porte sur la mémoire virtuelle et les fichiers mappés en mémoire : - - - :ref:`theorie:vmem` - - :ref:`theorie:fctvmem` - - :ref:`theorie:stockage` - - :ref:`theorie:remplacement` - - :ref:`theorie:mmap` +La matière de cette semaine porte sur l'utilisation du processeur intel 32 bits en langage assembleur + - `Organisation des ordinateurs <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html>`_ + - `Etude de cas : IA32 <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html#etude-de-cas-architecture-ia32>`_ -.. only:: html - - `QCM11 <http://sites.uclouvain.be/SystInfo/qcm/Mission-11-qcm.html>`_ Séance tutorée ^^^^^^^^^^^^^^ @@ -176,23 +197,24 @@ Séance tutorée .. toctree:: :maxdepth: 2 - Programmes/prog-11 + mcq-ex/qcm-4-asm + Programmes/prog-4-asm -Douzième semaine +Douzième semaine ---------------- -La matière de cette semaine porte sur les utilisations avancées de la mémoire virtuelle : +La matière de cette semaine porte sur les signaux, les sémaphores nommés et le partage de fichiers : - - :ref:`theorie:shmem` - - :ref:`theorie:forkmem` - - :ref:`theorie:vmstat` - - :ref:`theorie:execvmem` + - :ref:`theorie:signaux` -Séance tutorée + +Séance tutorée ^^^^^^^^^^^^^^ .. toctree:: - :maxdepth: 2 + :maxdepth: 2 + + mcq-ex/qcm-10 + Programmes/prog-10 - Programmes/prog-12 diff --git a/Exercices/links.rst b/Exercices/links.rst deleted file mode 100644 index 4b347abb839c72e9f85a61719cb89da0e9c7f706..0000000000000000000000000000000000000000 --- a/Exercices/links.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. Links to be included - - - -.. _intel : http://www.intel.com -.. _python : http://www.python.org -.. _perl : http://www.perl.org -.. _Git : http://git-scm.com/ -.. _subversion : http://subversion.apache.org/ -.. _ISO-8859 : http://en.wikipedia.org/wiki/ISO/IEC_8859 -.. _Unicode: http://en.wikipedia.org/wiki/Unicode -.. _Endianness: http://en.wikipedia.org/wiki/Endianness -.. _llvm: http://llvm.org - -.. |fsf| replace:: Free Software Foundation (FSF - http://www.fsf.org) -.. |gnu| replace:: GNU is Not Unix (GNU - http://www.gnu.org) - - - - diff --git a/Exercices/mcq-ex/qcm-1.rst b/Exercices/mcq-ex/qcm-1.rst index 3bf23fb3262651a83cc3362d320a11420978ff42..9cec8736f6daffe68a5dc5afb7ae29b67b187668 100644 --- a/Exercices/mcq-ex/qcm-1.rst +++ b/Exercices/mcq-ex/qcm-1.rst @@ -206,7 +206,7 @@ Question 4. Deuxième programme en langage C .. negative:: - .. code-block:: c + .. code-block:: none #include <stdio.h> int main(int argc, const char *argv[]) { @@ -218,7 +218,7 @@ Question 4. Deuxième programme en langage C .. negative:: - .. code-block:: c + .. code-block:: none #include <stdio.h> int main(int argc, const char *argv[]) { @@ -272,6 +272,7 @@ Question 5. Arguments passés à un programme C - Lors de l'exécution de la fonction ``main``, ``argc`` est initialisé au nombre d'arguments passés au programme (y compris le nom de l'exécutable lui-même). - Lors de l'exécution de la fonction ``main``, le tableau ``argv[]`` contient dans ``argv[0]`` le nom du programme, dans ``argv[1]`` le premier argument, etc. - La fonction ``atoi`` permet de convertir une chaîne de caractères en l'entier équivalent. + .. comment:: Réponse correcte. .. negative:: @@ -298,6 +299,3 @@ Question 5. Arguments passés à un programme C .. comment:: Le premier élément du tableau ``argv[]``, ``argv[0]``, est le nom du programme qui est exécuté. -.. include:: ../../links.rst -.. include:: ../../man_links.rst -.. include:: ../../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-10.rst b/Exercices/mcq-ex/qcm-10.rst index 04aa2ef412f3b691eedbfe91ec62770066993e7e..77d6ecfd31ccc6a59b051c2fe9454027ba950592 100644 --- a/Exercices/mcq-ex/qcm-10.rst +++ b/Exercices/mcq-ex/qcm-10.rst @@ -226,6 +226,3 @@ Deux stratégies existent pour implémenter les signaux sous Unix: maintenir une .. comment:: Si un autre signal arrive durant l'exécution de la routine de traitement de signal, celui-ci sera perdu car bloqué par le système d'exploitation pour empêcher l'interruption de la routine de traitement du précédent signal. -.. include:: ../links.rst -.. include:: ../man_links.rst -.. include:: ../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-2.rst b/Exercices/mcq-ex/qcm-2.rst index 4a7bc015bb8cb38b383c24dd90fbfe67fa3e7a58..a09a717c40ef0c4c32542b7258951de8a1abb283 100644 --- a/Exercices/mcq-ex/qcm-2.rst +++ b/Exercices/mcq-ex/qcm-2.rst @@ -362,7 +362,7 @@ Question 7. Extraction de bits Il est parfois nécessaire en C de manipuler directement la représentation binaire d'un nombre. Si ``f`` est un nombre de type ``float`` stocké sur 32 bits, laquelle des expressions ci-dessous peut-elle être intégrée dans ce code pour afficher positif ou négatif en fonction du signe de ce nombre ? - .. code-block:: c + .. code-block:: none if(<à compléter>) printf("positif\n"); @@ -481,7 +481,7 @@ Question 8. Chaînes de caractères .. negative:: - .. code-block:: c + .. code-block:: none int count1(char *s, char c) { int i=0; @@ -818,6 +818,3 @@ On veut pouvoir facilement écrire une fonction de type ``void`` qui remplace la -.. include:: ../../../links.rst -.. include:: ../../../man_links.rst -.. include:: ../../../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-3.rst b/Exercices/mcq-ex/qcm-3.rst index 6bfb027e0edafaec7d07f9d50a3ef8ec3e518418..e820e105f44b2039075cadfab57c6c3f5ffc08ab 100644 --- a/Exercices/mcq-ex/qcm-3.rst +++ b/Exercices/mcq-ex/qcm-3.rst @@ -187,14 +187,14 @@ Considérons le fragment de programme ci-dessous. .. positive:: - - la variable ``i`` déclarée et initialisée en ``ligne A`` est stockée dans la zone des variables non-initialisées + - la variable ``i`` déclarée en ``ligne A`` est stockée dans la zone des variables non-initialisées - l'argument ``i`` déclaré en ``ligne C`` est stocké sur la pile - la variable ``j`` déclarée en ``ligne D`` est stockée sur la pile - la variable ``k`` déclarée en ``ligne F`` est stockée sur la pile .. positive:: - - la variable ``i`` déclarée et initialisée en ``ligne A`` est stockée dans la zone des variables non-initialisées + - la variable ``i`` déclarée en ``ligne A`` est stockée dans la zone des variables non-initialisées - le tableau ``tab`` déclaré en ``ligne B`` est stocké dans la zone des variables non-initialisées - l'argument ``i`` déclaré en ``ligne C`` est stocké sur la pile - la variable ``i`` déclarée en ``ligne E`` est stockée sur la pile @@ -596,6 +596,3 @@ Question 7. `strdup(3)`_ -.. include:: ../../../links.rst -.. include:: ../../../man_links.rst -.. include:: ../../../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-4-asm.rst b/Exercices/mcq-ex/qcm-4-asm.rst new file mode 100644 index 0000000000000000000000000000000000000000..e978d0865fd7a975a362383565c6b384c28f0bb3 --- /dev/null +++ b/Exercices/mcq-ex/qcm-4-asm.rst @@ -0,0 +1,1666 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + + +Questions à choix multiples +=========================== + +:task_id: sinf1252-4 + +Cette semaine, la matière porte sur l'organisation de la mémoire et sur le langage assembleur IA32. La matière couverte se trouve dans les sections suivantes du syllabus : + + - `Organisation des ordinateurs <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html>`_ + - `Etude de cas : IA32 <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html#etude-de-cas-architecture-ia32>`_ + +Question 1. Instruction ``mov`` +------------------------------- + +Les instructions de la famille ``mov`` permettent de déplacer des données entre registres ou d'initialiser des registres. Considérons le fragment de code C suivant (dans lequel ``g``, ``g2`` et ``s`` sont des variables globales de type ``int``) : + +.. code-block:: c + + g=1234; + g2=5678; + s=g; + g=g2; + g2=s; + +.. question:: mov + :nb_prop: 3 + :nb_pos: 1 + + Parmi les traductions en assembleur ci-dessus, une seule est correcte. Laquelle ? + + + .. positive:: + + + .. code-block:: nasm + + movl $1234, g + movl $5678, g2 + movl g, %ecx + movl %ecx, s + movl g2, %ecx + movl %ecx, g + movl s, %ecx + movl %ecx, g2 + + .. positive:: + + .. code-block:: nasm + + movl $1234, g + movl $5678, g2 + movl g, %eax + movl %eax, s + movl g2, %eax + movl %eax, g + movl s, %eax + movl %eax, g2 + + + .. negative:: + + + .. code-block:: nasm + + movl g, $1234 + movl g2, $5678 + movl %eax, g + movl s, %eax + movl %eax, g2 + movl g, %eax + movl s, %eax + movl g2, %eax + + .. comment:: L'instruction ``mov`` prend comme premier argument la source et comme second la destination. + + .. negative:: + + .. code-block:: nasm + + movl $1234, g + movl $5678, g2 + movl g2, %eax + movl %edx, s + movl g, %eax + movl %edx, g2 + movl s, %eax + movl %eax, g2 + + .. comment:: Ce code utilise les registres ``%edx`` et ``%eax``. ``%edx`` est utilisé sans être initialisé. + + .. negative:: + + .. code-block:: nasm + + movw $1234, g + movw $5678, g2 + movb g2, %eax + movb %eax, s + movb g, %eax + movb %eax, g2 + movb s, %eax + movb %eax, g2 + + .. comment:: L'instruction ``movb`` déplace un ``byte`` et non le contenu complet d'un registre de 32 bits. + + .. negative:: + + .. code-block:: nasm + + movw $1234, g + movw $5678, g2 + movb g2, %edx + movb %edx, s + movb g, %edx + movb %edx, g2 + movb s, %edx + movb %edx, g2 + + + .. comment:: + + L'instruction ``movb`` déplace un ``byte`` et non le contenu complet d'un registre de 32 bits. + +Question 2. Opérations arithmétiques +------------------------------------ + +Considérons le fragment de programme C ci-dessous : + + .. code-block:: c + + a=a+b; + b=b+b; + c=b-a; + +.. question:: add + :nb_prop: 3 + :nb_pos: 1 + + Une seule des séquences d'instructions assembleur ci-dessous est une traduction correcte de cette séquence d'instructions. Laquelle ? + + .. positive:: + + + .. code-block:: nasm + + movl a, %eax + addl b, %eax + movl %eax, a + movl b, %eax + addl b, %eax + movl %eax, b + movl b, %eax + subl a, %eax + movl %eax, c + + .. positive:: + + .. code-block:: nasm + + movl b, %eax + addl a, %eax + movl %eax, a + movl b, %eax + addl b, %eax + movl %eax, b + movl b, %eax + subl a, %eax + movl %eax, c + + + .. negative:: + + .. code-block:: nasm + + movl b, %eax + addl a, %eax + movl %eax, a + movl b, %eax + movl %eax, %ecx + addl $1, %ecx + movl %ecx, b + movl %eax, b + movl a, %eax + subl b, %eax + movl %eax, c + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + a=b+a; + b=b++; + c=a-b; + + .. negative:: + + .. code-block:: nasm + + movl b, %eax + addl a, %eax + movl %eax, c + movl b, %eax + movl %eax, %ecx + addl $1, %ecx + movl %ecx, b + movl %eax, b + movl a, %eax + subl b, %eax + movl %eax, a + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + c=b+a; + b=b++; + a=a-b; + + .. negative:: + + .. code-block:: nasm + + movl b, %eax + addl a, %eax + movl %eax, b + movl b, %eax + movl %eax, %ecx + addl $1, %ecx + movl %ecx, b + movl %eax, a + movl b, %eax + subl a, %eax + movl %eax, c + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + b=b+a; + a=b++; + c=b-a; + +Question 3. Instructions conditionnelles +---------------------------------------- + +Les instructions conditionnelles sont fréquemment utilisées en langage C et en assembleur. Considérons le fragment de programme C ci-dessous (``a`` et ``b`` sont des variables globales de type ``int``): + + .. code-block:: c + + if(b<4) + a++; + +.. question:: conditionnelles + :nb_prop: 3 + :nb_pos: 1 + + Une seule des séquences d'instructions assembleur ci-dessous est une traduction correcte de cette séquence d'instructions. Laquelle ? + + .. positive:: + + + .. code-block:: nasm + + begin: + cmpl $4, b + jge end + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + .. positive:: + + .. code-block:: nasm + + begin: + cmpl $4, b + jl next + jmp end + next: + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if((b>=4)) + {} + else + a++; + + + .. negative:: + + + + .. code-block:: nasm + + begin: + cmpl $4, b + jg end + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(b<=4) + a++; + + + .. negative:: + + .. code-block:: nasm + + begin: + cmpl $4, b + je end + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(b!=4) + a++; + + .. negative:: + + .. code-block:: nasm + + begin: + cmpl $4, b + jl end + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(!(b<4)) + a++; + + .. negative:: + + .. code-block:: nasm + + begin: + cmpl $4, b + jl end + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(b>=4) + a++; + + +Question 4. Instructions conditionnelles +---------------------------------------- + +Les instructions conditionnelles sont fréquemment utilisées en langage C et en assembleur. Considérons le fragment de programme C ci-dessous : + + .. code-block:: c + + if(a<=b) + c++; + +.. question:: conditionnelles2 + :nb_prop: 3 + :nb_pos: 1 + + Une seule des séquences d'instructions en assembleur ci-dessous correspond à ce fragment de code C. Laquelle ? + + + .. positive:: + + + .. code-block:: nasm + + if: + movl a, %eax + cmpl b, %eax + jg next + movl c, %eax + addl $1, %eax + movl %eax, c + next: + + .. positive:: + + .. code-block:: nasm + + if: + movl b, %eax + cmpl a, %eax + jl next + movl c, %eax + addl $1, %eax + movl %eax, c + next: + + .. comment:: + + Ceci est en fait l'implémentation de : + + .. code-block:: c + + if(b>=a) + c++; + + + .. negative:: + + + .. code-block:: nasm + + if: + movl a, %eax + cmpl b, %eax + jne next + movl c, %eax + addl $1, %eax + movl %eax, c + next: + + .. comment:: + + Ceci est l'implémentation de : + + .. code-block:: c + + if(a==b) + c++; + + .. negative:: + + .. code-block:: nasm + + if: + movl a, %eax + cmpl b, %eax + jle next + movl c, %eax + addl $1, %eax + movl %eax, c + next: + + .. comment:: + + Ceci est l'implémentation de : + + .. code-block:: c + + if(a>b) + c++; + + .. negative:: + + .. code-block:: none + + if: + movl a, %eax + cmpl b, %eax + jge next + movl c, %eax + addl $1, %eax + movl %eax, c + next: + + + .. comment:: + + Ceci est l'implémentation de : + + .. code-block:: c + + if(a<b) + c++; + + .. negative:: + + .. code-block:: nasm + + if: + movl a, %eax + cmpl b, %eax + je next + movl c, %eax + addl $1, %eax + movl %eax, c + next: + + .. comment:: + + Ceci est l'implémentation de : + + .. code-block:: c + + if(a!=b) + c++; + + + +Question 5. Instructions conditionnelles +---------------------------------------- + +L'instruction conditionnelle ``if() ... else`` se retrouve dans de nombreux programmes en langage C. Considérons l'instruction ``if() ... else`` simple ci-dessous dans laquelle ``a`` et ``b`` sont des variables globales de type ``int`` : + +.. code-block:: c + + if(a>=b) + a++; + else + b++; + +.. question:: conditionnelles3 + :nb_prop: 3 + :nb_pos: 1 + + Parmi les séquences d'assembleur ci-dessous, une seule est une traduction correcte de cette instruction conditionnelle. Laquelle ? + + .. positive:: + + + .. code-block:: nasm + + movl a, %eax + cmpl b, %eax + jl label + movl a, %eax + addl $1, %eax + movl %eax, a + jmp end + label: + movl b, %eax + addl $1, %eax + movl %eax, b + end: + + .. positive:: + + .. code-block:: nasm + + movl b, %eax + cmpl a, %eax + jg label + movl a, %eax + addl $1, %eax + movl %eax, a + jmp end + label: + movl b, %eax + addl $1, %eax + movl %eax, b + end: + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(b<=a) + a++; + else + b++; + + + .. negative:: + + .. code-block:: nasm + + + movl a, %eax + cmpl b, %eax + jl label + movl b, %eax + addl $1, %eax + movl %eax, b + jmp end + label: + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(a>=b) + b++; + else + a++; + + .. negative:: + + .. code-block:: nasm + + + movl b, %eax + cmpl a, %eax + jge label + movl a, %eax + addl $1, %eax + movl %eax, a + jmp end + label: + movl b, %eax + addl $1, %eax + movl %eax, b + end: + + + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(b<a) + a++; + else + b++; + + .. negative:: + + .. code-block:: nasm + + movl b, %eax + cmpl a, %eax + jle label + movl b, %eax + addl $1, %eax + movl %eax, b + jmp .LBB4_3 + label: + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(b>a) + b++; + else + a++; + + .. negative:: + + .. code-block:: nasm + + movl a, %eax + cmpl b, %eax + jl label + movl a, %eax + addl $1, %eax + movl %eax, a + label: + movl b, %eax + addl $1, %eax + movl %eax, b + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + if(a>=b) { + a++; + } + b++; + + + +Question 6. Boucles ``while`` +----------------------------- + +Les boucles ``while`` sont fréquemment utilisées dans des programmes C. Considérons la boucle suivante qui utilise des variables globales (toutes de type ``int``): + + .. code-block:: c + + while(a!=c) + { + a++; + b=b+c; + } + +.. question:: while + :nb_prop: 3 + :nb_pos: 1 + + Parmi les séquences d'assembleur ci-dessous, une seule est une traduction correcte de cette boucle ``while``. Laquelle ? + + .. positive:: + + + .. code-block:: nasm + + begin: + movl a, %eax + cmpl c, %eax + je end + movl a, %eax + addl $1, %eax + movl %eax, a + movl b, %eax + addl c, %eax + movl %eax, b + jmp begin + end: + + .. positive:: + + .. code-block:: nasm + + begin: + movl c, %eax + cmpl a, %eax + je end + movl a, %eax + addl $1, %eax + movl %eax, a + movl b, %eax + addl c, %eax + movl %eax, b + jmp begin + end: + + + .. negative:: + + + .. code-block:: nasm + + begin: + movl c, %eax + cmpl a, %eax + jle end + movl a, %eax + addl $1, %eax + movl %eax, a + movl b, %eax + addl c, %eax + movl %eax, b + jmp begin + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + while(c>a) + { + a++; + b=b+c; + } + + .. negative:: + + .. code-block:: nasm + + begin: + movl a, %eax + addl $1, %eax + movl %eax, a + movl b, %eax + addl c, %eax + movl %eax, b + movl c, %eax + cmpl a, %eax + jne begin + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + do + { + a++; + b=b+c; + } + while(c!=a); + + .. negative:: + + .. code-block:: nasm + + begin: + movl c, %eax + cmpl a, %eax + jne end + movl a, %eax + addl $1, %eax + movl %eax, a + movl b, %eax + addl c, %eax + movl %eax, b + jmp begin + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + while(c==a) + { + a++; + b=b+c; + } + + +Question 7. Boucles ``for`` +--------------------------- + +Rares sont les programmes C qui ne contiennent pas de boucles ``for``. Considérons la boucle ci-dessous qui utilise uniquement des variables globales (de type ``int``) : + +.. code-block:: c + + for(a=0;a<c;a++) { + b=b-c; + } + +.. question:: for + :nb_prop: 3 + :nb_pos: 1 + + Parmi les séquences d'instructions en assembleur ci-dessous, une seule traduit correctement la boucle ``for`` ci-dessus. Laquelle ? + + + .. positive:: + + + .. code-block:: nasm + + begin: + movl $0, a + loop: + movl a, %eax + cmpl c, %eax + jge end + movl b, %eax + subl c, %eax + movl %eax, b + movl a, %eax + addl $1, %eax + movl %eax, a + jmp loop + end: + + .. positive:: + + .. code-block:: nasm + + begin: + movl $0, a + loop: + movl c, %eax + cmpl a, %eax + jle end + movl b, %eax + subl c, %eax + movl %eax, b + movl a, %eax + addl $1, %eax + movl %eax, a + jmp loop + end: + + .. negative:: + + + .. code-block:: nasm + + begin: + movl a, %eax + addl $1, %eax + movl %eax, a + loop: + movl c, %eax + cmpl a, %eax + jle end + movl b, %eax + subl c, %eax + movl %eax, b + movl $0, a + jmp loop + end: + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + for(a=a+1;c>a;a=0) { + b=b-c; + } + + .. negative:: + + .. code-block:: nasm + + begin: + movl $0, a + loop: + movl a, %eax + cmpl c, %eax + jg end + movl b, %eax + subl c, %eax + movl %eax, b + movl a, %eax + addl $1, %eax + movl %eax, a + jmp loop + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + for(a=0;a<=c;a++) { + b=b-c; + } + + .. negative:: + + .. code-block:: nasm + + begin: + movl $0, a + movl a, %eax + cmpl c, %eax + jge end + movl b, %eax + subl c, %eax + movl %eax, b + movl a, %eax + addl $1, %eax + movl %eax, a + end: + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + a=0; + if(a<c) { + b=b-c; + a++; + } + + .. negative:: + + .. code-block:: nasm + + begin: + loop: + movl a, %eax + cmpl c, %eax + jge end + movl $0, a + movl b, %eax + subl c, %eax + movl %eax, b + movl a, %eax + addl $1, %eax + movl %eax, a + jmp loop + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + for(;a<c;a++) { + a=0; + b=b-c; + } + + +Question 8. Fonctions +--------------------- + +Un programme C contient en général de nombreuses fonctions. Considérons une fonction simple qui effectue un calcul en utilisant un argument et une variable globale (``a``) : + +.. code-block:: c + + + int f(int i) + { + return i+a; + } + + +.. question:: fonction + :nb_prop: 3 + :nb_pos: 1 + + Parmi les séquences d'instructions en assembleur ci-dessous, une seule traduit correctement la fonction ci-dessus. Laquelle ? + + .. positive:: + + .. code-block:: nasm + + pushl %eax + movl 8(%esp), %eax + movl %eax, (%esp) + movl (%esp), %eax + addl a, %eax + popl %edx + ret + + + .. positive:: + + .. code-block:: nasm + + subl $8, %esp + movl 12(%esp), %eax + movl %eax, 4(%esp) + movl a, %eax + movl %eax, (%esp) + movl (%esp), %eax + addl 4(%esp), %eax + addl $8, %esp + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int f(int i) + { + int j=a; + return j+i; + } + + + .. negative:: + + + .. code-block:: nasm + + subl $8, %esp + movl 12(%esp), %eax + movl %eax, 4(%esp) + movl 4(%esp), %eax + addl a, %eax + movl %eax, (%esp) + addl $8, %esp + ret + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + void f3(int i) // incorrect + { + int j=i+a; + } + + .. negative:: + + .. code-block:: nasm + + pushl %eax + movl (%esp), %eax + addl a, %eax + popl %edx + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + + int f() + { + int i; + return i+a; + } + + .. negative:: + + .. code-block:: nasm + + pushl %eax + movb 8(%esp), %al + movb %al, 3(%esp) + movsbl 3(%esp), %ecx + addl a, %ecx + movl %ecx, %eax + popl %edx + ret + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int f(char c) + { + return c+a; + } + + .. negative:: + + .. code-block:: nasm + + pushl %eax + movb 8(%esp), %al + movb %al, 3(%esp) + movsbl 3(%esp), %ecx + addl a, %ecx + movb %cl, %al + movsbl %al, %eax + popl %edx + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + char f(char c) + { + return c+a; + } + + + + + +Question 9. Fonction ``max`` +---------------------------- + +Considérons la fonction C qui calcule le maximum entre deux entiers : + +.. code-block:: c + + int max(int i, int j) { + if (i>j) + return i; + else + return j; + } + +.. question:: max + :nb_prop: 3 + :nb_pos: 1 + + Parmi les groupes d'instructions ci-dessous, un seul est la traduction de cette fonction. Lequel ? + + .. positive:: + + .. code-block:: nasm + + + max: + subl $12, %esp + movl 20(%esp), %eax + movl 16(%esp), %ecx + movl %ecx, 4(%esp) + movl %eax, (%esp) + movl 4(%esp), %eax + cmpl (%esp), %eax + jle next + movl 4(%esp), %eax + movl %eax, 8(%esp) + jmp label + next: + movl (%esp), %eax + movl %eax, 8(%esp) + label: + movl 8(%esp), %eax + addl $12, %esp + ret + + .. positive:: + + .. code-block:: nasm + + max2: + subl $12, %esp + movl 20(%esp), %eax + movl 16(%esp), %ecx + movl %ecx, 4(%esp) + movl %eax, (%esp) + movl 4(%esp), %eax + cmpl (%esp), %eax + jge label1 + movl (%esp), %eax + movl %eax, 8(%esp) + jmp label2 + label1: + movl 4(%esp), %eax + movl %eax, 8(%esp) + label2: + movl 8(%esp), %eax + addl $12, %esp + ret + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int max(int i, int j) { + if (i<j) + return j; + else + return i; + } + + + .. negative:: + + + .. code-block:: nasm + + max: + subl $8, %esp + movl 12(%esp), %eax + movl %eax, (%esp) + movl (%esp), %eax + cmpl (%esp), %eax + jge label1 + movl (%esp), %eax + movl %eax, 4(%esp) + jmp label2 + label1: + movl (%esp), %eax + movl %eax, 4(%esp) + label2: + movl 4(%esp), %eax + addl $8, %esp + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + + int max(int i) { + if (i<i) + return i; + else + return i; + } + + .. negative:: + + .. code-block:: nasm + + max: + subl $12, %esp + movl 20(%esp), %eax + movl 16(%esp), %ecx + movl %ecx, 4(%esp) + movl %eax, (%esp) + movl 4(%esp), %eax + cmpl (%esp), %eax + jge label1 + movl (%esp), %eax + movl %eax, 8(%esp) + jmp label2 + label1: + movl (%esp), %eax + movl %eax, 8(%esp) + label2: + movl 8(%esp), %eax + addl $12, %esp + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int max4(int i, int j) { //incorrect + if (i<j) + return j; + else + return j; + } + + .. negative:: + + .. code-block:: nasm + + max: + subl $12, %esp + movl 20(%esp), %eax + movl 16(%esp), %ecx + movl %ecx, 4(%esp) + movl %eax, (%esp) + movl 4(%esp), %eax + cmpl (%esp), %eax + jge label1 + movl 4(%esp), %eax + movl %eax, 8(%esp) + jmp label2 + label1: + movl (%esp), %eax + movl %eax, 8(%esp) + label2: + movl 8(%esp), %eax + addl $12, %esp + ret + + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int max5(int i, int j) { + if (i<j) + return i; + else + return j; + } + +Question 10. Fonctions récursives +--------------------------------- + +Les fonctions récursives sont parfois utilisées en langage C. Lors de leur exécution, la pile permet de stocker temporairement les valeurs des variables et les adresses de retour. Considérons la fonction récursive suivante (où ``a`` est une variable globale) : + +.. code-block:: c + + int f(int i) + { + return a+f(i-1); + } + +.. question:: recursive + :nb_prop: 3 + :nb_pos: 1 + + Parmi les séquences d'instructions assembleur ci-dessous, une seule est une traduction correctement de cette fonction. Laquelle ? + + .. positive:: + + + .. code-block:: nasm + + + f: + pushl %ebp + movl %esp, %ebp + subl $12, %esp + movl 8(%ebp), %eax + movl %eax, -4(%ebp) + movl a, %eax + movl -4(%ebp), %ecx + subl $1, %ecx + movl %ecx, (%esp) + movl %eax, -8(%ebp) + calll f + movl -8(%ebp), %ecx + addl %eax, %ecx + movl %ecx, %eax + addl $12, %esp + popl %ebp + ret + + .. positive:: + + .. code-block:: nasm + + f: + pushl %ebp + movl %esp, %ebp + subl $12, %esp + movl 8(%ebp), %eax + movl %eax, -4(%ebp) + movl -4(%ebp), %eax + subl $1, %eax + movl %eax, (%esp) + calll f + movl %eax, -8(%ebp) + movl -8(%ebp), %eax + addl a, %eax + addl $12, %esp + popl %ebp + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int f(int i) + { + int j=f(i-1); + return j+a; + } + + + .. negative:: + + + .. code-block:: nasm + + f: + pushl %ebp + movl %esp, %ebp + subl $12, %esp + movl 8(%ebp), %eax + movl %eax, -4(%ebp) + movl a, %eax + movl -4(%ebp), %ecx + movl %ecx, (%esp) + movl %eax, -8(%ebp) + calll f + movl -8(%ebp), %ecx + addl %eax, %ecx + movl %ecx, %eax + addl $12, %esp + popl %ebp + ret + + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int f(int i) + { + return a+f(i); + } + + .. negative:: + + .. code-block:: nasm + + f: + pushl %ebp + movl %esp, %ebp + subl $8, %esp + movl 8(%ebp), %eax + movl %eax, -4(%ebp) + movl -4(%ebp), %eax + addl a, %eax + movl %eax, (%esp) + calll f + addl $8, %esp + popl %ebp + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int f(int i) // incorrect + { + return f(i+a); + } + + .. negative:: + + .. code-block:: nasm + + pushl %ebp + movl %esp, %ebp + subl $12, %esp + movl 8(%ebp), %eax + movl %eax, -4(%ebp) + movl -4(%ebp), %eax + subl $1, %eax + movl %eax, (%esp) + calll f + movl %eax, -8(%ebp) + movl a, %eax + addl $12, %esp + popl %ebp + ret + + .. comment:: + + Ceci est la traduction de : + + .. code-block:: c + + int f(int i) + { + int j=f(i-1); + return a; + } + + +Question 10. Pointeurs en assembleur +------------------------------------ + +Pour comprendre le fonctionnement des pointeurs en C, il est parfois utile de se ramener à la traduction en assembleur de fragments de code C. Considérons les lignes suivantes : + + .. code-block:: c + + int a=1252; + int * ptr; + + int main(int argc, const char *argv[]) { + ptr=&a; + } + +.. question:: ptrasm + :nb_prop: 3 + :nb_pos: 1 + + Parmi les séquences d'instructions en assembleur ci-dessous, une seule est la traduction de l'assignation de l'adresse de ``a`` au pointeur ``ptr``. Laquelle + + .. positive:: + + + .. code-block:: nasm + + leal a, %eax + movl %eax, ptr + + .. negative:: + + + .. code-block:: nasm + + movl a, %eax + movl ptr, %ecx + movl %eax, (%ecx) + + .. comment:: Cette séquence d'instructions est la traduction de ``*ptr=a``. + + .. negative:: + + .. code-block:: nasm + + movl a, %eax + movl %eax, ptr + + .. comment:: Cette séquence d'instructions est la traduction de ``ptr=(int )a;``. + + .. negative:: + + + .. code-block:: nasm + + pushl %eax + leal (%esp), %eax + movl a, %ecx + movl %ecx, (%esp) + movl %eax, ptr + popl %eax + + .. comment:: + + Cette séquence d'instructions est la traduction de : + + .. code-block:: c + + int b=a; + ptr=&(b); + + .. negative:: + + + .. code-block:: nasm + + leal a, %eax + addl $4, %eax + movl %eax, ptr + + .. comment:: + + Cette séquence d'instructions est la traduction de ``ptr=&a+1;``. + + diff --git a/Exercices/mcq-ex/qcm-4.rst b/Exercices/mcq-ex/qcm-4.rst index 80c9b5cabd43c4f6237b056d5b3f340409a92b86..d55932bffad1a498c61ac3f83cc93ad106f45c75 100644 --- a/Exercices/mcq-ex/qcm-4.rst +++ b/Exercices/mcq-ex/qcm-4.rst @@ -8,1580 +8,308 @@ Questions à choix multiples :task_id: sinf1252-4 -Cette semaine, la matière porte sur l'organisation de la mémoire et sur le langage assembleur IA32. La matière couverte se trouve dans les sections suivantes du syllabus : - - `Organisation des ordinateurs <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html>`_ - - `Etude de cas : IA32 <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Assembleur/memory.html#etude-de-cas-architecture-ia32>`_ - -Question 1. Instruction ``mov`` -------------------------------- +Question 1. Pointeurs et tableaux +--------------------------------- -Les instructions de la famille ``mov`` permettent de déplacer des données entre registres ou d'initialiser des registres. Considérons le fragment de code C suivant (dans lequel ``g``, ``g2`` et ``s`` sont des variables globales de type ``int``) : +Les pointeurs peuvent être utilisés pour accéder à des tableaux. Considérons un fragment de code C utilisant un tableau d'entiers à une dimension : .. code-block:: c - g=1234; - g2=5678; - s=g; - g=g2; - g2=s; - -.. question:: mov - :nb_prop: 3 - :nb_pos: 1 - - Parmi les traductions en assembleur ci-dessus, une seule est correcte. Laquelle ? - - - .. positive:: - - - .. code-block:: nasm - - movl $1234, g - movl $5678, g2 - movl g, %ecx - movl %ecx, s - movl g2, %ecx - movl %ecx, g - movl s, %ecx - movl %ecx, g2 - - .. positive:: - - .. code-block:: nasm - - movl $1234, g - movl $5678, g2 - movl g, %eax - movl %eax, s - movl g2, %eax - movl %eax, g - movl s, %eax - movl %eax, g2 - - - .. negative:: - - - .. code-block:: nasm - - movl g, $1234 - movl g2, $5678 - movl %eax, g - movl s, %eax - movl %eax, g2 - movl g, %eax - movl s, %eax - movl g2, %eax - - .. comment:: L'instruction ``mov`` prend comme premier argument la source et comme second la destination. - - .. negative:: + int a[]={2,4,3,4,8}; + int * ptr; - .. code-block:: nasm + printf("%d %d %d %d\n",a[0],a[1],a[2],a[a[3]]); - movl $1234, g - movl $5678, g2 - movl g2, %eax - movl %edx, s - movl g, %eax - movl %edx, g2 - movl s, %eax - movl %eax, g2 - .. comment:: Ce code utilise les registres ``%edx`` et ``%eax``. ``%edx`` est utilisé sans être initialisé. +Lors de son exécution, ce programme affiche ``2 4 3 8`` sur sa sortie standard. - .. negative:: - - .. code-block:: nasm - - movw $1234, g - movw $5678, g2 - movb g2, %eax - movb %eax, s - movb g, %eax - movb %eax, g2 - movb s, %eax - movb %eax, g2 - - .. comment:: L'instruction ``movb`` déplace un ``byte`` et non le contenu complet d'un registre de 32 bits. - - .. negative:: - - .. code-block:: nasm - - movw $1234, g - movw $5678, g2 - movb g2, %edx - movb %edx, s - movb g, %edx - movb %edx, g2 - movb s, %edx - movb %edx, g2 - - - .. comment:: - - L'instruction ``movb`` déplace un ``byte`` et non le contenu complet d'un registre de 32 bits. - -Question 2. Opérations arithmétiques ------------------------------------- - -Considérons le fragment de programme C ci-dessous : - - .. code-block:: c - - a=a+b; - b=b+b; - c=b-a; - -.. question:: add +.. question:: ptr-tableaux :nb_prop: 3 :nb_pos: 1 - Une seule des séquences d'instructions assembleur ci-dessous est une traduction correcte de cette séquence d'instructions. Laquelle ? - - .. positive:: - - - .. code-block:: nasm - - movl a, %eax - addl b, %eax - movl %eax, a - movl b, %eax - addl b, %eax - movl %eax, b - movl b, %eax - subl a, %eax - movl %eax, c + Après exécution de ``ptr=&(a[0]);``, une seule des instructions ci-dessous affiche la même séquence de chiffres. Laquelle ? .. positive:: - .. code-block:: nasm - movl b, %eax - addl a, %eax - movl %eax, a - movl b, %eax - addl b, %eax - movl %eax, b - movl b, %eax - subl a, %eax - movl %eax, c + .. code-block:: c + printf("%d %d %d %d\n",*ptr,*(ptr+1),*(ptr+2),*(ptr+*(ptr+3))); .. negative:: - .. code-block:: nasm + .. code-block:: c - movl b, %eax - addl a, %eax - movl %eax, a - movl b, %eax - movl %eax, %ecx - addl $1, %ecx - movl %ecx, b - movl %eax, b - movl a, %eax - subl b, %eax - movl %eax, c + printf("%d %d %d %d\n",*ptr,*ptr+1,*ptr+2,*(ptr+*(ptr+3))); .. comment:: - Ceci est la traduction de : - - .. code-block:: c + Cette ligne affiche ``2 3 4 8``. Sur base des règles de précédence entre les opérations, l'expression ``*ptr+1`` équivaut en fait à ``(*ptr)+1``. En cas de doute, utilisez les parenthèses. - a=b+a; - b=b++; - c=a-b; .. negative:: - .. code-block:: nasm + .. code-block:: c - movl b, %eax - addl a, %eax - movl %eax, c - movl b, %eax - movl %eax, %ecx - addl $1, %ecx - movl %ecx, b - movl %eax, b - movl a, %eax - subl b, %eax - movl %eax, a + printf("%d %d %d %d\n",*ptr,*(ptr++),(*ptr++),*(ptr+*(ptr++))); .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - c=b+a; - b=b++; - a=a-b; - - .. negative:: - - .. code-block:: nasm - - movl b, %eax - addl a, %eax - movl %eax, b - movl b, %eax - movl %eax, %ecx - addl $1, %ecx - movl %ecx, b - movl %eax, a - movl b, %eax - subl a, %eax - movl %eax, c - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - b=b+a; - a=b++; - c=b-a; - -Question 3. Instructions conditionnelles ----------------------------------------- - -Les instructions conditionnelles sont fréquemment utilisées en langage C et en assembleur. Considérons le fragment de programme C ci-dessous (``a`` et ``b`` sont des variables globales de type ``int``): - - .. code-block:: c - - if(b<4) - a++; - -.. question:: conditionnelles - :nb_prop: 3 - :nb_pos: 1 - - Une seule des séquences d'instructions assembleur ci-dessous est une traduction correcte de cette séquence d'instructions. Laquelle ? - - .. positive:: - - - .. code-block:: nasm - - begin: - cmpl $4, b - jge end - movl a, %eax - addl $1, %eax - movl %eax, a - end: - - .. positive:: - - .. code-block:: nasm - - begin: - cmpl $4, b - jl next - jmp end - next: - movl a, %eax - addl $1, %eax - movl %eax, a - end: - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if((b>=4)) - {} - else - a++; - + Cette ligne affiche ``2 2 4 ???``. La dernière expression ``*(ptr+*(ptr++))`` accède une zone de mémoire en dehors du tableau et dont la valeur est inconnue (notez que la valeur de ``ptr++`` est la valeur de ptr AVANT l'incrémentation, contrairement à ``++ptr``). .. negative:: + .. code-block:: c - - .. code-block:: nasm - - begin: - cmpl $4, b - jg end - movl a, %eax - addl $1, %eax - movl %eax, a - end: + printf("%d %d %d %d\n",*ptr,*(ptr+0),*(ptr+1),*ptr+*(ptr+2)); .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - if(b<=4) - a++; - + Cette ligne affiche ``2 2 4 5``. ``*(ptr+0)`` est ``a[0]`` et non ``a[1]``. .. negative:: - .. code-block:: nasm - - begin: - cmpl $4, b - je end - movl a, %eax - addl $1, %eax - movl %eax, a - end: - + .. code-block:: c + printf("%d %d %d %d\n",*ptr,*ptr+1,(*ptr+1),*(ptr+(ptr+3))); .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - if(b!=4) - a++; - - .. negative:: - - .. code-block:: nasm - - begin: - cmpl $4, b - jl end - movl a, %eax - addl $1, %eax - movl %eax, a - end: + Cette ligne est syntaxiquement invalide. L'expression ``ptr+(ptr+3)`` est invalide. On ne peut pas additionner deux pointeurs. - .. comment:: - - Ceci est la traduction de : - .. code-block:: c +Question 2. Traitement de ``argv`` +---------------------------------- - if(!(b<4)) - a++; - - .. negative:: - - .. code-block:: nasm - - begin: - cmpl $4, b - jl end - movl a, %eax - addl $1, %eax - movl %eax, a - end: - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if(b>=4) - a++; - - -Question 4. Instructions conditionnelles ----------------------------------------- - -Les instructions conditionnelles sont fréquemment utilisées en langage C et en assembleur. Considérons le fragment de programme C ci-dessous : - - .. code-block:: c - - if(a<=b) - c++; - -.. question:: conditionnelles2 - :nb_prop: 3 - :nb_pos: 1 - - Une seule des séquences d'instructions en assembleur ci-dessous correspond à ce fragment de code C. Laquelle ? - - - .. positive:: - - - .. code-block:: nasm - - if: - movl a, %eax - cmpl b, %eax - jg next - movl c, %eax - addl $1, %eax - movl %eax, c - next: - - .. positive:: - - .. code-block:: nasm - - if: - movl b, %eax - cmpl a, %eax - jl next - movl c, %eax - addl $1, %eax - movl %eax, c - next: - - .. comment:: - - Ceci est en fait l'implémentation de : - - .. code-block:: c - - if(b>=a) - c++; - - - .. negative:: - - - .. code-block:: nasm - - if: - movl a, %eax - cmpl b, %eax - jne next - movl c, %eax - addl $1, %eax - movl %eax, c - next: - - .. comment:: - - Ceci est l'implémentation de : - - .. code-block:: c - - if(a==b) - c++; - - .. negative:: - - .. code-block:: nasm - - if: - movl a, %eax - cmpl b, %eax - jle next - movl c, %eax - addl $1, %eax - movl %eax, c - next: - - .. comment:: - - Ceci est l'implémentation de : - - .. code-block:: c - - if(a>b) - c++; - - .. negative:: - - .. code-block:: nasm - - - if: - movl a, %eax - cmpl b, %eax - jge next - movl c, %eax - addl $1, %eax - movl %eax, c - next: - - - .. comment:: - - Ceci est l'implémentation de : - - .. code-block:: c - - if(a<b) - c++; - - .. negative:: - - .. code-block:: nasm - - if: - movl a, %eax - cmpl b, %eax - je next - movl c, %eax - addl $1, %eax - movl %eax, c - next: - - .. comment:: - - Ceci est l'implémentation de : - - .. code-block:: c - - if(a!=b) - c++; - - - -Question 5. Instructions conditionnelles ----------------------------------------- - -L'instruction conditionnelle ``if() ... else`` se retrouve dans de nombreux programmes en langage C. Considérons l'instruction ``if() ... else`` simple ci-dessous dans laquelle ``a`` et ``b`` sont des variables globales de type ``int`` : +Un programme C doit souvent pouvoir manipuler les arguments qui lui sont passés. Les variables ``argc`` et ``argv`` qui sont passées à la fonction ``main`` permettent d'accéder à ces arguments. Le fragment de programme ci-dessous affiche sur la sortie standard ses différents arguments. .. code-block:: c - if(a>=b) - a++; - else - b++; - -.. question:: conditionnelles3 - :nb_prop: 3 - :nb_pos: 1 - - Parmi les séquences d'assembleur ci-dessous, une seule est une traduction correcte de cette instruction conditionnelle. Laquelle ? - - .. positive:: - - - .. code-block:: nasm - - movl a, %eax - cmpl b, %eax - jl label - movl a, %eax - addl $1, %eax - movl %eax, a - jmp end - label: - movl b, %eax - addl $1, %eax - movl %eax, b - end: - - .. positive:: - - .. code-block:: nasm - - movl b, %eax - cmpl a, %eax - jg label - movl a, %eax - addl $1, %eax - movl %eax, a - jmp end - label: - movl b, %eax - addl $1, %eax - movl %eax, b - end: - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if(b<=a) - a++; - else - b++; - - - .. negative:: - - .. code-block:: nasm - - - movl a, %eax - cmpl b, %eax - jl label - movl b, %eax - addl $1, %eax - movl %eax, b - jmp end - label: - movl a, %eax - addl $1, %eax - movl %eax, a - end: - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if(a>=b) - b++; - else - a++; - - .. negative:: - - .. code-block:: nasm - - - movl b, %eax - cmpl a, %eax - jge label - movl a, %eax - addl $1, %eax - movl %eax, a - jmp end - label: - movl b, %eax - addl $1, %eax - movl %eax, b - end: - - - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if(b<a) - a++; - else - b++; - - .. negative:: - - .. code-block:: nasm - - movl b, %eax - cmpl a, %eax - jle label - movl b, %eax - addl $1, %eax - movl %eax, b - jmp .LBB4_3 - label: - movl a, %eax - addl $1, %eax - movl %eax, a - end: - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if(b>a) - b++; - else - a++; - - .. negative:: - - .. code-block:: nasm - - movl a, %eax - cmpl b, %eax - jl label - movl a, %eax - addl $1, %eax - movl %eax, a - label: - movl b, %eax - addl $1, %eax - movl %eax, b - end: - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - if(a>=b) { - a++; - } - b++; - - - -Question 6. Boucles ``while`` ------------------------------ + while(i<argc) { + printf("%d %p %s\n",i,&(argv[i]),argv[i]); + i++; + } -Les boucles ``while`` sont fréquemment utilisées dans des programmes C. Considérons la boucle suivante qui utilise des variables globales (toutes de type ``int``): +Un exemple d'exécution de ce fragment de programme est présenté ci-dessous : - .. code-block:: c +.. code-block:: console - while(a!=c) - { - a++; - b=b+c; - } + #./a.out a b cd + 0 0x7fff5fbff788 ./a.out + 1 0x7fff5fbff790 a + 2 0x7fff5fbff798 b + 3 0x7fff5fbff7a0 cd -.. question:: while +.. question:: argv :nb_prop: 3 :nb_pos: 1 - Parmi les séquences d'assembleur ci-dessous, une seule est une traduction correcte de cette boucle ``while``. Laquelle ? + A côté de la notation ``argv[i]``, il est aussi possible d'accéder à ``argv`` en utilisant des pointeurs. Parmi les fragments de programme ci-dessous, un seul est correct et affiche le même résultat que ci-dessus. .. positive:: - .. code-block:: nasm + .. code-block:: c - begin: - movl a, %eax - cmpl c, %eax - je end - movl a, %eax - addl $1, %eax - movl %eax, a - movl b, %eax - addl c, %eax - movl %eax, b - jmp begin - end: - - .. positive:: - - .. code-block:: nasm - - begin: - movl c, %eax - cmpl a, %eax - je end - movl a, %eax - addl $1, %eax - movl %eax, a - movl b, %eax - addl c, %eax - movl %eax, b - jmp begin - end: + char **ptr; + int i=0; + ptr=argv; + while(i<argc) { + printf("%d %p %s\n",i,&(*ptr),*ptr); + i++; + ptr++; + } .. negative:: + .. code-block:: c - .. code-block:: nasm + char **ptr; + int i=0; + ptr=argv; + while(i<argc) { + printf("%d %p %s\n",i,&(ptr),*ptr); + i++; + ptr++; + } - begin: - movl c, %eax - cmpl a, %eax - jle end - movl a, %eax - addl $1, %eax - movl %eax, a - movl b, %eax - addl c, %eax - movl %eax, b - jmp begin - end: .. comment:: - Ceci est la traduction de : + ``&(ptr)`` est l'adresse à laquelle le pointeur ``ptr`` est stocké. Notez que ce n'est pas l'adresse à laquelle la chaîne de caractère argument ``i`` est stockée. Ce programme affiche : - .. code-block:: c + .. code-block:: console - while(c>a) - { - a++; - b=b+c; - } + 0 0x7fff5fbff738 ./a.out + 1 0x7fff5fbff738 a + 2 0x7fff5fbff738 b + 3 0x7fff5fbff738 cd .. negative:: - .. code-block:: nasm - - begin: - movl a, %eax - addl $1, %eax - movl %eax, a - movl b, %eax - addl c, %eax - movl %eax, b - movl c, %eax - cmpl a, %eax - jne begin - end: - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - do - { - a++; - b=b+c; - } - while(c!=a); - - .. negative:: + .. code-block:: c - .. code-block:: nasm - - begin: - movl c, %eax - cmpl a, %eax - jne end - movl a, %eax - addl $1, %eax - movl %eax, a - movl b, %eax - addl c, %eax - movl %eax, b - jmp begin - end: + char *ptr; + int i=0; + ptr=*argv; + while(i<argc) { + printf("%d %p %s\n",i,&(ptr),*ptr); + i++; + ptr++; + } .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - while(c==a) - { - a++; - b=b+c; - } - - -Question 7. Boucles ``for`` ---------------------------- - -Rares sont les programmes C qui ne contiennent pas de boucles ``for``. Considérons la boucle ci-dessous qui utilise uniquement des variables globales (de type ``int``) : - -.. code-block:: c - - for(a=0;a<c;a++) { - b=b-c; - } - -.. question:: for - :nb_prop: 3 - :nb_pos: 1 - - Parmi les séquences d'instructions en assembleur ci-dessous, une seule traduit correctement la boucle ``for`` ci-dessus. Laquelle ? - - - .. positive:: - - - .. code-block:: nasm - - begin: - movl $0, a - loop: - movl a, %eax - cmpl c, %eax - jge end - movl b, %eax - subl c, %eax - movl %eax, b - movl a, %eax - addl $1, %eax - movl %eax, a - jmp loop - end: - - .. positive:: - - .. code-block:: nasm - - begin: - movl $0, a - loop: - movl c, %eax - cmpl a, %eax - jle end - movl b, %eax - subl c, %eax - movl %eax, b - movl a, %eax - addl $1, %eax - movl %eax, a - jmp loop - end: + Notez dans ce code que ``ptr`` est déclaré comme ``char *``, alors que ``argv`` est un ``char **``. Si vous tenez d'exécutez ce code, il provoquera un segmentation fault. .. negative:: + .. code-block:: c - .. code-block:: nasm - - begin: - movl a, %eax - addl $1, %eax - movl %eax, a - loop: - movl c, %eax - cmpl a, %eax - jle end - movl b, %eax - subl c, %eax - movl %eax, b - movl $0, a - jmp loop - end: - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - for(a=a+1;c>a;a=0) { - b=b-c; - } - - .. negative:: - - .. code-block:: nasm - - begin: - movl $0, a - loop: - movl a, %eax - cmpl c, %eax - jg end - movl b, %eax - subl c, %eax - movl %eax, b - movl a, %eax - addl $1, %eax - movl %eax, a - jmp loop - end: + int i=0; + while(i<argc) { + printf("%d %p %s\n",i,&(argv+i),*(argv+i)); + i++; + } .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - for(a=0;a<=c;a++) { - b=b-c; - } + La compilation de ce fragment de programme provoque un warning. L'expression ``&(argv+i)`` est invalide car ``argv`` est un pointeur (de type ``char **``) et donc ``argv+i`` est également une adresse en mémoire et l'opérateur ``&`` ne peut pas s'y appliquer. .. negative:: - .. code-block:: nasm - - begin: - movl $0, a - movl a, %eax - cmpl c, %eax - jge end - movl b, %eax - subl c, %eax - movl %eax, b - movl a, %eax - addl $1, %eax - movl %eax, a - end: - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - a=0; - if(a<c) { - b=b-c; - a++; - } + .. code-block:: c - .. negative:: + int i=0; + while(i<argc) { + printf("%d %p %s\n",i,&(*(argv+i)),(argv+i)); + i++; + } - .. code-block:: nasm - - begin: - loop: - movl a, %eax - cmpl c, %eax - jge end - movl $0, a - movl b, %eax - subl c, %eax - movl %eax, b - movl a, %eax - addl $1, %eax - movl %eax, a - jmp loop .. comment:: - Ceci est la traduction de : - - .. code-block:: c + Dans ce fragment de code, ``argv+i`` est de type ``char **`` alors qu'il faut un ``char *`` pour passer un string à `printf(3)`_. - for(;a<c;a++) { - a=0; - b=b-c; - } -Question 8. Fonctions ---------------------- +Question 3. Pointeurs et tableaux à deux dimensions +--------------------------------------------------- -Un programme C contient en général de nombreuses fonctions. Considérons une fonction simple qui effectue un calcul en utilisant un argument et une variable globale (``a``) : +En C, il est possible d'accéder aux données stockées dans un tableau à deux dimensions via la notation ``a[i][j]`` mais aussi en utilisant des pointeurs. Considérons le fragment de code ci-dessous : .. code-block:: c + int m[3][4]= { { 1, 2, 3, 4} , + { 5, 6, 7, 8} , + { 9, 10, 11, 12} }; - int f(int i) - { - return i+a; - } - + printf("%p %d %d %d\n",m, m[1][2], m[0][5], m[2][2]); -.. question:: fonction - :nb_prop: 3 - :nb_pos: 1 - Parmi les séquences d'instructions en assembleur ci-dessous, une seule traduit correctement la fonction ci-dessus. Laquelle ? +Un compilateur Java n'accepterait pas de compiler ce programme qui tente d'accéder à l'élément ``m[0][5]`` de la matrice, élément qui n'existe pas sur base de l'initialisation du tableau ``m``. De nombreux compilateurs C acceptent ce fragment de code sans contrainte. Lorsque le programme s'exécute il affiche : - .. positive:: +.. code-block:: console - .. code-block:: nasm + 0x7fff5fbff750 7 6 11 - pushl %eax - movl 8(%esp), %eax - movl %eax, (%esp) - movl (%esp), %eax - addl a, %eax - popl %edx - ret +.. question:: ptr-tableaux2d + :nb_prop: 3 + :nb_pos: 1 + Parmi les fragments de programme ci-dessous, un seul utilisant la notation avec les pointeurs est correct et affiche la même sortie. Lequel ? .. positive:: - .. code-block:: nasm - - subl $8, %esp - movl 12(%esp), %eax - movl %eax, 4(%esp) - movl a, %eax - movl %eax, (%esp) - movl (%esp), %eax - addl 4(%esp), %eax - addl $8, %esp - ret - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - int f(int i) - { - int j=a; - return j+i; - } - - - .. negative:: - - - .. code-block:: nasm - subl $8, %esp - movl 12(%esp), %eax - movl %eax, 4(%esp) - movl 4(%esp), %eax - addl a, %eax - movl %eax, (%esp) - addl $8, %esp - ret - - - .. comment:: + .. code-block:: c - Ceci est la traduction de : + int *ptr; - .. code-block:: c + ptr=&(m[0][0]); + printf("%p %d %d %d\n",ptr, *(ptr+4*1+2), *(ptr+4*0+5), *(ptr+2*4+2)); - void f3(int i) // incorrect - { - int j=i+a; - } .. negative:: - .. code-block:: nasm + .. code-block:: c - pushl %eax - movl (%esp), %eax - addl a, %eax - popl %edx - ret + int **ptr=m; + printf("%p %d %d %d\n",ptr, *(ptr+4*1+2), *(ptr+4*0+5), *(ptr+2*4+2)); .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - - int f() - { - int i; - return i+a; - } + La déclaration ``int **ptr=m`` est invalide. .. negative:: - .. code-block:: nasm - - pushl %eax - movb 8(%esp), %al - movb %al, 3(%esp) - movsbl 3(%esp), %ecx - addl a, %ecx - movl %ecx, %eax - popl %edx - ret - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - int f(char c) - { - return c+a; - } - - .. negative:: + .. code-block:: c - .. code-block:: nasm + int *ptr=m; + printf("%p %d %d %d\n",ptr, *(ptr+4*1+2), *(ptr+4*0+5), *(ptr+2*4+2)); - pushl %eax - movb 8(%esp), %al - movb %al, 3(%esp) - movsbl 3(%esp), %ecx - addl a, %ecx - movb %cl, %al - movsbl %al, %eax - popl %edx - ret .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - char f(char c) - { - return c+a; - } - - - - + La déclaration ``int *ptr=m;`` est invalide, ``m`` n'est pas de type ``int *``. -Question 9. Fonction ``max`` ----------------------------- - -Considérons la fonction C qui calcule le maximum entre deux entiers : - -.. code-block:: c - - int max(int i, int j) { - if (i>j) - return i; - else - return j; - } - -.. question:: max +Question 4. Variable ``errno`` +------------------------------ +.. question:: errno :nb_prop: 3 :nb_pos: 1 - Parmi les groupes d'instructions ci-dessous, un seul est la traduction de cette fonction. Lequel ? - - .. positive:: - - .. code-block:: nasm - - - max: - subl $12, %esp - movl 20(%esp), %eax - movl 16(%esp), %ecx - movl %ecx, 4(%esp) - movl %eax, (%esp) - movl 4(%esp), %eax - cmpl (%esp), %eax - jle next - movl 4(%esp), %eax - movl %eax, 8(%esp) - jmp label - next: - movl (%esp), %eax - movl %eax, 8(%esp) - label: - movl 8(%esp), %eax - addl $12, %esp - ret + En C, la variable ``errno`` est utilisée par le système pour fournir une indication sur une erreur qui s'est produite lors de l'exécution d'un appel système ou d'une fonction de la librairie. Parmi les fonctions ci-dessous, une seule ne modifie pas ``errno`` en cas d'erreur. Laquelle ? .. positive:: - .. code-block:: nasm - - max2: - subl $12, %esp - movl 20(%esp), %eax - movl 16(%esp), %ecx - movl %ecx, 4(%esp) - movl %eax, (%esp) - movl 4(%esp), %eax - cmpl (%esp), %eax - jge label1 - movl (%esp), %eax - movl %eax, 8(%esp) - jmp label2 - label1: - movl 4(%esp), %eax - movl %eax, 8(%esp) - label2: - movl 8(%esp), %eax - addl $12, %esp - ret - - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - int max(int i, int j) { - if (i<j) - return j; - else - return i; - } - - - .. negative:: - - - .. code-block:: nasm - - max: - subl $8, %esp - movl 12(%esp), %eax - movl %eax, (%esp) - movl (%esp), %eax - cmpl (%esp), %eax - jge label1 - movl (%esp), %eax - movl %eax, 4(%esp) - jmp label2 - label1: - movl (%esp), %eax - movl %eax, 4(%esp) - label2: - movl 4(%esp), %eax - addl $8, %esp - ret - - .. comment:: - - Ceci est la traduction de : - - .. code-block:: c - - - int max(int i) { - if (i<i) - return i; - else - return i; - } - - .. negative:: - - .. code-block:: nasm - - max: - subl $12, %esp - movl 20(%esp), %eax - movl 16(%esp), %ecx - movl %ecx, 4(%esp) - movl %eax, (%esp) - movl 4(%esp), %eax - cmpl (%esp), %eax - jge label1 - movl (%esp), %eax - movl %eax, 8(%esp) - jmp label2 - label1: - movl (%esp), %eax - movl %eax, 8(%esp) - label2: - movl 8(%esp), %eax - addl $12, %esp - ret + `getpid(2)`_ .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - int max4(int i, int j) { //incorrect - if (i<j) - return j; - else - return j; - } + Voir page de manuel. .. negative:: - .. code-block:: nasm - - max: - subl $12, %esp - movl 20(%esp), %eax - movl 16(%esp), %ecx - movl %ecx, 4(%esp) - movl %eax, (%esp) - movl 4(%esp), %eax - cmpl (%esp), %eax - jge label1 - movl 4(%esp), %eax - movl %eax, 8(%esp) - jmp label2 - label1: - movl (%esp), %eax - movl %eax, 8(%esp) - label2: - movl 8(%esp), %eax - addl $12, %esp - ret - - + `malloc(3)`_ .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - int max5(int i, int j) { - if (i<j) - return i; - else - return j; - } - -Question 10. Fonctions récursives ---------------------------------- - -Les fonctions récursives sont parfois utilisées en langage C. Lors de leur exécution, la pile permet de stocker temporairement les valeurs des variables et les adresses de retour. Considérons la fonction récursive suivante (où ``a`` est une variable globale) : - -.. code-block:: c - - int f(int i) - { - return a+f(i-1); - } - -.. question:: recursive - :nb_prop: 3 - :nb_pos: 1 - - Parmi les séquences d'instructions assembleur ci-dessous, une seule est une traduction correctement de cette fonction. Laquelle ? - - .. positive:: - - - .. code-block:: nasm - - - f: - pushl %ebp - movl %esp, %ebp - subl $12, %esp - movl 8(%ebp), %eax - movl %eax, -4(%ebp) - movl a, %eax - movl -4(%ebp), %ecx - subl $1, %ecx - movl %ecx, (%esp) - movl %eax, -8(%ebp) - calll f - movl -8(%ebp), %ecx - addl %eax, %ecx - movl %ecx, %eax - addl $12, %esp - popl %ebp - ret + Notez que `malloc(3)`_ retourne ``NULL`` en cas d'erreur d'allocation mais met ENONMEM comme erreur dans ``errno`` .. positive:: - .. code-block:: nasm - - f: - pushl %ebp - movl %esp, %ebp - subl $12, %esp - movl 8(%ebp), %eax - movl %eax, -4(%ebp) - movl -4(%ebp), %eax - subl $1, %eax - movl %eax, (%esp) - calll f - movl %eax, -8(%ebp) - movl -8(%ebp), %eax - addl a, %eax - addl $12, %esp - popl %ebp - ret + `exit(2)`_ .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - int f(int i) - { - int j=f(i-1); - return j+a; - } - + Comme cette fonction ne se termine jamais, elle ne peux pas modifier ``errno``. .. negative:: - - .. code-block:: nasm - - f: - pushl %ebp - movl %esp, %ebp - subl $12, %esp - movl 8(%ebp), %eax - movl %eax, -4(%ebp) - movl a, %eax - movl -4(%ebp), %ecx - movl %ecx, (%esp) - movl %eax, -8(%ebp) - calll f - movl -8(%ebp), %ecx - addl %eax, %ecx - movl %ecx, %eax - addl $12, %esp - popl %ebp - ret - + `setenv(3)`_ .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - int f(int i) - { - return a+f(i); - } + Voir page de manuel. .. negative:: - .. code-block:: nasm - - f: - pushl %ebp - movl %esp, %ebp - subl $8, %esp - movl 8(%ebp), %eax - movl %eax, -4(%ebp) - movl -4(%ebp), %eax - addl a, %eax - movl %eax, (%esp) - calll f - addl $8, %esp - popl %ebp - ret + `unsetenv(3)`_ .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - int f(int i) // incorrect - { - return f(i+a); - } + Voir page de manuel. .. negative:: - .. code-block:: nasm - - pushl %ebp - movl %esp, %ebp - subl $12, %esp - movl 8(%ebp), %eax - movl %eax, -4(%ebp) - movl -4(%ebp), %eax - subl $1, %eax - movl %eax, (%esp) - calll f - movl %eax, -8(%ebp) - movl a, %eax - addl $12, %esp - popl %ebp - ret + `pthread_join(3)`_ .. comment:: - Ceci est la traduction de : - - .. code-block:: c - - int f(int i) - { - int j=f(i-1); - return a; - } + Voir page de manuel et aussi http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html. La plupart des fonctions pthread_* ne modifient pas la valeur de ``errno``, mais le standard n'est pas 100% clair sur ce qu'une implémentation doit faire. Linux ne semble pas fixer la valeur de ``errno``. -.. include:: ../../links.rst -.. include:: ../../man_links.rst -.. include:: ../../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-5.rst b/Exercices/mcq-ex/qcm-5.rst.old similarity index 52% rename from Exercices/mcq-ex/qcm-5.rst rename to Exercices/mcq-ex/qcm-5.rst.old index 3d66901b3ae42132c56813b4d9c30596c13acbc8..82f2193b520b8d2b748833fa261d94082fafe41c 100644 --- a/Exercices/mcq-ex/qcm-5.rst +++ b/Exercices/mcq-ex/qcm-5.rst.old @@ -99,309 +99,6 @@ Pour comprendre le fonctionnement des pointeurs en C, il est parfois utile de se Cette séquence d'instructions est la traduction de ``ptr=&a+1;``. -Question 2. Pointeurs et tableaux ---------------------------------- - -Les pointeurs peuvent être utilisés pour accéder à des tableaux. Considérons un fragment de code C utilisant un tableau d'entiers à une dimension : - -.. code-block:: c - - int a[]={2,4,3,4,8}; - int * ptr; - - printf("%d %d %d %d\n",a[0],a[1],a[2],a[a[3]]); - - -Lors de son exécution, ce programme affiche ``2 4 3 8`` sur sa sortie standard. - -.. question:: ptr-tableaux - :nb_prop: 3 - :nb_pos: 1 - - Après exécution de ``ptr=&(a[0]);``, une seule des instructions ci-dessous affiche la même séquence de chiffres. Laquelle ? - - .. positive:: - - - .. code-block:: c - - printf("%d %d %d %d\n",*ptr,*(ptr+1),*(ptr+2),*(ptr+*(ptr+3))); - - .. negative:: - - .. code-block:: c - - printf("%d %d %d %d\n",*ptr,*ptr+1,*ptr+2,*(ptr+*(ptr+3))); - - .. comment:: - - Cette ligne affiche ``2 3 4 8``. Sur base des règles de précédence entre les opérations, l'expression ``*ptr+1`` équivaut en fait à ``(*ptr)+1``. En cas de doute, utilisez les parenthèses. - - - .. negative:: - - .. code-block:: c - - printf("%d %d %d %d\n",*ptr,*(ptr++),(*ptr++),*(ptr+*(ptr++))); - - .. comment:: - - Cette ligne affiche ``2 2 4 ???``. La dernière expression ``*(ptr+*(ptr++))`` accède une zone de mémoire en dehors du tableau et dont la valeur est inconnue (notez que la valeur de ``ptr++`` est la valeur de ptr AVANT l'incrémentation, contrairement à ``++ptr``). - - .. negative:: - - .. code-block:: c - - printf("%d %d %d %d\n",*ptr,*(ptr+0),*(ptr+1),*ptr+*(ptr+2)); - - .. comment:: - - Cette ligne affiche ``2 2 4 5``. ``*(ptr+0)`` est ``a[0]`` et non ``a[1]``. - - .. negative:: - - .. code-block:: c - - printf("%d %d %d %d\n",*ptr,*ptr+1,(*ptr+1),*(ptr+(ptr+3))); - - .. comment:: - - Cette ligne est syntaxiquement invalide. L'expression ``ptr+(ptr+3)`` est invalide. On ne peut pas additionner deux pointeurs. - - - -Question 3. Traitement de ``argv`` ----------------------------------- - -Un programme C doit souvent pouvoir manipuler les arguments qui lui sont passés. Les variables ``argc`` et ``argv`` qui sont passées à la fonction ``main`` permettent d'accéder à ces arguments. Le fragment de programme ci-dessous affiche sur la sortie standard ses différents arguments. - -.. code-block:: c - - while(i<argc) { - printf("%d %p %s\n",i,&(argv[i]),argv[i]); - i++; - } - -Un exemple d'exécution de ce fragment de programme est présenté ci-dessous : - -.. code-block:: console - - #./a.out a b cd - 0 0x7fff5fbff788 ./a.out - 1 0x7fff5fbff790 a - 2 0x7fff5fbff798 b - 3 0x7fff5fbff7a0 cd - -.. question:: argv - :nb_prop: 3 - :nb_pos: 1 - - A côté de la notation ``argv[i]``, il est aussi possible d'accéder à ``argv`` en utilisant des pointeurs. Parmi les fragments de programme ci-dessous, un seul est correct et affiche le même résultat que ci-dessus. - - .. positive:: - - - .. code-block:: c - - char **ptr; - int i=0; - ptr=argv; - while(i<argc) { - printf("%d %p %s\n",i,&(*ptr),*ptr); - i++; - ptr++; - } - - - .. negative:: - - .. code-block:: c - - char **ptr; - int i=0; - ptr=argv; - while(i<argc) { - printf("%d %p %s\n",i,&(ptr),*ptr); - i++; - ptr++; - } - - - .. comment:: - - ``&(ptr)`` est l'adresse à laquelle le pointeur ``ptr`` est stocké. Notez que ce n'est pas l'adresse à laquelle la chaîne de caractère argument ``i`` est stockée. Ce programme affiche : - - .. code-block:: console - - 0 0x7fff5fbff738 ./a.out - 1 0x7fff5fbff738 a - 2 0x7fff5fbff738 b - 3 0x7fff5fbff738 cd - - .. negative:: - - .. code-block:: c - - char *ptr; - int i=0; - ptr=*argv; - while(i<argc) { - printf("%d %p %s\n",i,&(ptr),*ptr); - i++; - ptr++; - } - - .. comment:: - - Notez dans ce code que ``ptr`` est déclaré comme ``char *``, alors que ``argv`` est un ``char **``. Si vous tenez d'exécutez ce code, il provoquera un segmentation fault. - - .. negative:: - - .. code-block:: c - - int i=0; - while(i<argc) { - printf("%d %p %s\n",i,&(argv+i),*(argv+i)); - i++; - } - - .. comment:: - - La compilation de ce fragment de programme provoque un warning. L'expression ``&(argv+i)`` est invalide car ``argv`` est un pointeur (de type ``char **``) et donc ``argv+i`` est également une adresse en mémoire et l'opérateur ``&`` ne peut pas s'y appliquer. - - .. negative:: - - .. code-block:: c - - int i=0; - while(i<argc) { - printf("%d %p %s\n",i,&(*(argv+i)),(argv+i)); - i++; - } - - - .. comment:: - - Dans ce fragment de code, ``argv+i`` est de type ``char **`` alors qu'il faut un ``char *`` pour passer un string à `printf(3)`_. - - - -Question 4. Pointeurs et tableaux à deux dimensions ---------------------------------------------------- - -En C, il est possible d'accéder aux données stockées dans un tableau à deux dimensions via la notation ``a[i][j]`` mais aussi en utilisant des pointeurs. Considérons le fragment de code ci-dessous : - -.. code-block:: c - - int m[3][4]= { { 1, 2, 3, 4} , - { 5, 6, 7, 8} , - { 9, 10, 11, 12} }; - - printf("%p %d %d %d\n",m, m[1][2], m[0][5], m[2][2]); - - -Un compilateur Java n'accepterait pas de compiler ce programme qui tente d'accéder à l'élément ``m[0][5]`` de la matrice, élément qui n'existe pas sur base de l'initialisation du tableau ``m``. De nombreux compilateurs C acceptent ce fragment de code sans contrainte. Lorsque le programme s'exécute il affiche : - -.. code-block:: console - - 0x7fff5fbff750 7 6 11 - -.. question:: ptr-tableaux2d - :nb_prop: 3 - :nb_pos: 1 - - Parmi les fragments de programme ci-dessous, un seul utilisant la notation avec les pointeurs est correct et affiche la même sortie. Lequel ? - - .. positive:: - - - .. code-block:: c - - int *ptr; - - ptr=&(m[0][0]); - printf("%p %d %d %d\n",ptr, *(ptr+4*1+2), *(ptr+4*0+5), *(ptr+2*4+2)); - - - .. negative:: - - .. code-block:: c - - int **ptr=m; - printf("%p %d %d %d\n",ptr, *(ptr+4*1+2), *(ptr+4*0+5), *(ptr+2*4+2)); - - .. comment:: - - La déclaration ``int **ptr=m`` est invalide. - - .. negative:: - - .. code-block:: c - - int *ptr=m; - printf("%p %d %d %d\n",ptr, *(ptr+4*1+2), *(ptr+4*0+5), *(ptr+2*4+2)); - - - .. comment:: - - La déclaration ``int *ptr=m;`` est invalide, ``m`` n'est pas de type ``int *``. - -Question 5. Variable ``errno`` ------------------------------- -.. question:: errno - :nb_prop: 3 - :nb_pos: 1 - - En C, la variable ``errno`` est utilisée par le système pour fournir une indication sur une erreur qui s'est produite lors de l'exécution d'un appel système ou d'une fonction de la librairie. Parmi les fonctions ci-dessous, une seule ne modifie pas ``errno`` en cas d'erreur. Laquelle ? - - .. positive:: - - `getpid(2)`_ - - .. comment:: - - Voir page de manuel. - - .. negative:: - - `malloc(3)`_ - - .. comment:: - - Notez que `malloc(3)`_ retourne ``NULL`` en cas d'erreur d'allocation mais met ENONMEM comme erreur dans ``errno`` - - .. positive:: - - `exit(2)`_ - - .. comment:: - - Comme cette fonction ne se termine jamais, elle ne peux pas modifier ``errno``. - - .. negative:: - - `setenv(3)`_ - - .. comment:: - - Voir page de manuel. - - .. negative:: - - `unsetenv(3)`_ - - .. comment:: - - Voir page de manuel. - - .. negative:: - - `pthread_join(3)`_ - - .. comment:: - - Voir page de manuel et aussi http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html. La plupart des fonctions pthread_* ne modifient pas la valeur de ``errno``, mais le standard n'est pas 100% clair sur ce qu'une implémentation doit faire. Linux ne semble pas fixer la valeur de ``errno``. - Question 6. Utilisation de `pthread_create(3)`_ ------------------------------------------------ diff --git a/Exercices/mcq-ex/qcm-6.rst b/Exercices/mcq-ex/qcm-6.rst new file mode 100644 index 0000000000000000000000000000000000000000..e850fd7c20da2ab1eb79cefd3c136125ef583a99 --- /dev/null +++ b/Exercices/mcq-ex/qcm-6.rst @@ -0,0 +1,722 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + + +Questions à choix multiples +=========================== + +:task_id: sinf1252-6 + +Cette semaine porte sur la communication et la synchronisation entre threads. Plus précisément, la matière est décrite dans les deux sections suivantes : + + - :ref:`theorie:threads` (sauf la section `Utilisation d'instruction atomique`) + - :ref:`theorie:comthreads` (jusqu'à la section `Le problème des philosophes`) + +.. - `Communication entre threads <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Threads/threads2.html>`_ +.. - `Coordination entre threads <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Threads/threads2.html#coordination-entre-threads>`_ + + + + +Question 1. Utilisation de `pthread_create(3)`_ +------------------------------------------------ + + +.. question:: pthread_create + :nb_prop: 3 + :nb_pos: 1 + + + La fonction `pthread_create(3)`_ permet de créer un thread. Parmi les fragments de code ci-dessous, un seul crée correctement un thread qui appelle la fonction ``f`` en lui passant la chaîne de caractères ``s`` comme argument. Lequel ? + + .. positive:: + + .. code-block:: c + + void * f( void * param) { + // incomplet + return NULL; + } + + int main (int argc, char *argv[]) { + + pthread_t t; + int err; + char *s; + err=pthread_create(&t,NULL,&(f),(void *) s); + } + + + .. negative:: + + .. code-block:: c + + void * f (void * param) { + // incomplet + return NULL; + } + + int main (int argc, char *argv[]) { + + pthread_t t; + int err; + char *s; + err=pthread_create(&t,NULL,&(f),(void *) &s); + } + + .. comment:: Ce fragment contient une erreur. La fonction ``f`` a la bonne signature, mais le dernier argument à `pthread_create(3)`_ doit être de type ``void *``, or ``s`` est un ``char *`` et donc ce dernier argument doit être ``(void *) s``. + + .. negative:: + + .. code-block:: c + + void f(void * param) { + // incomplet + return NULL; + } + + int main (int argc, char *argv[]) { + + pthread_t *t; + int err; + char *s; + err=pthread_create(t,NULL,*f,(void *) *s); + } + + .. comment:: Ce fragment contient plusieurs erreurs. La fonction ``f`` n'a pas la bonne signature (d'ailleurs ``return NULL;`` pour une fonction ``void`` est incorrect). Ensuite, l'appel à `pthread_create(3)`_ doit prendre comme premier argument l'adresse vers une structure de type ``pthread_t`` qui est stockée en mémoire. Ce n'est pas le cas ici. Les troisième et quatrième arguments sont également incorrects. + + .. negative:: + + .. code-block:: c + + + void *f(void ** param) { + // incomplet + return NULL; + } + + int main (int argc, char *argv[]) { + + pthread_t t; + int err; + char s; + err=pthread_create(&t,NULL,&(f),(void *) s); + } + + .. comment:: Dans ce fragment de code, la signature de la fonction ``f`` ainsi que l'appel à `pthread_create(3)`_ sont incorrects. + + + +Question 2. Passage d'arguments à un thread +------------------------------------------- + +Considérons un thread qui a pour objectif de convertir une fraction en un nombre en virgule flottante. Ce n'est pas une bonne utilisation de threads puisque le calcul à effectuer est très simple, mais cela nous permettra de voir comment un thread peut recevoir des arguments directement. En dehors des threads, cette fonction de conversion pourrait s'écrire : + +.. code-block:: c + + struct fraction { + int num; + int denum; + }; + + typedef struct fraction Fraction_t; + + float tofloat(Fraction_t t) { + return (float) t.num/ (float) t.denum; + } + +.. question:: argthread + :nb_prop: 3 + :nb_pos: 1 + + Parmi les programmes ci-dessous, un seul calcule correctement la valeur attendue (le test des valeurs de retour des fonctions n'est pas présenté pour garder le code concis). Lequel ? + + + .. positive:: + + + .. code-block:: c + + void *mythread(void * param) { + Fraction_t *f=(Fraction_t *) param; + float *r=(float *)malloc(sizeof(float)); + *r=(float) f->num/ (float) f->denum; + return((void *) r); + } + + int main (int argc, char *argv[]) { + + pthread_t t; + Fraction_t f; + f.num=1; + f.denum=3; + float *r; + int err; + + err=pthread_create(&t,NULL,&mythread,&(f)); + + err=pthread_join(t,(void **) &r); + + } + + + .. negative:: + + .. code-block:: c + + void *mythread(void * param) { + Fraction_t f= *param; + float r; + r=(float) f.num/ (float) f.denum; + return((void *) &r); + } + + int main (int argc, char *argv[]) { + + pthread_t t; + Fraction_t f; + f.num=1; + f.denum=3; + float r; + int err; + + err=pthread_create(&t,NULL,&mythread,&(f)); + + err=pthread_join(t,(void **) &r); + + } + + .. comment:: La fonction ``mythread`` est incorrect. L'initialisation de ``f`` ne fonctionne pas et en plus le résultat de la fonction est une variable locale (``r``) qui disparaît après son exécution. L'adresse de cette variable, même en étant castée en ``void *`` ne peut pas être retournée à la fonction ``main``. + + .. negative:: + + .. code-block:: c + + + void *mythread(void * param) { + Fraction_t *t=(Fraction_t *) param; + float *r=(float *)malloc(sizeof(float)); + *r=(float) t->num/ (float) t->denum; + return((void *) r); + } + + int main (int argc, char *argv[]) { + + pthread_t t; + Fraction_t f; + f.num=1; + f.denum=3; + float r; + int err; + + err=pthread_create(&t,NULL,&mythread,&f); + r=pthread_join(t,NULL); + + } + + .. comment:: Dans cette variable, l'appel à `pthread_join(3)`_ est incorrect. + + .. negative:: + + .. code-block:: c + + float mythread(Fraction_t param) { + float *r=(float *)malloc(sizeof(float)); + *r=(float) param->num/ (float) param->denum; + return(r); + } + + int main (int argc, char *argv[]) { + pthread_t t; + Fraction_t f; + f.num=1; + f.denum=3; + printf("%f \n",tofloat(f)); + float *r; + int err; + + err=pthread_create(&t,NULL,&mythread,&(f)); + + err=pthread_join(t,(void *) &r); + } + + .. comment:: Cette variante contient deux erreurs. La première est le prototype de la fonction ``mythread``. Celle-ci doit obligatoirement être de type ``void * fct(void * param)``, il n'est pas possible d'utiliser un autre prototype. Ensuite, l'appel à `pthread_join(3)`_ est incorrect puisque le deuxième argument de `pthread_join(3)`_ doit être de type ``void **`` et non ``void *``. + + +Question 3. Algorithme de Peterson +---------------------------------- + +.. question:: peterson + :nb_prop: 3 + :nb_pos: 1 + + L'algorithme de Peterson peut s'écrire de différentes façons. Pour bien comprendre son fonctionnement, il est utile de réfléchir à d'autres formulations que celle utilisées dans le syllabus. Parmi les fragments de code ci-dessous, un seul implémente correctement l'algorithme de Peterson. Lequel ? + + + .. positive:: + + .. code-block:: c + + /* initialisation */ + bool in1 = false; + bool in2 = false; + int last = 1; + // thread 1 + while (true) { + in1 = true; + last = 1; + while ( in2 && (last==1)) {}; + section_critique(); + in1=false; + // ... + } + // thread2 + while (true) { + in2 = true; + last = 2; + while ( in1 && (last==2)) {}; + section_critique(); + in2=false; + // ... + } + + .. positive:: + + .. code-block:: c + + /* initialisation */ + bool in1 = false; + bool in2 = false; + int last = 2; + // thread 1 + while (true) { + in1 = true; + last = 1; + while ( in2 && (last==1)) {}; + section_critique(); + in1=false; + // ... + } + // thread2 + while (true) { + in2 = true; + last = 2; + while ( in1 && (last==2)) {}; + section_critique(); + in2=false; + // ... + } + + .. negative:: + + + .. code-block:: c + + // initialisation + bool in1 = false; + bool in2 = false; + int last = 1; + // thread 1 + while (true) { + in1 = true; + last = 1; + while ( in1 && (last==1)) {}; + section_critique(); + in1=false; + // ... + } + // thread2 + while (true) { + in2 = true; + last = 2; + while ( in2 && (last==2)) {}; + section_critique(); + in2=false; + // ... + } + + .. comment:: + + Cette solution ne fonctionne pas. Si un des deux threads est seul, il n'entrera jamais en section critique. + + .. negative:: + + .. code-block:: c + + // initialisation + bool in1 = false; + bool in2 = false; + int last = 2; + // thread 1 + while (true) { + in1 = true; + last = 1; + while ( in2 && (last==2)) {}; + section_critique(); + in1=false; + // ... + } + // thread2 + while (true) { + in2 = true; + last = 2; + while ( in1 && (last==1)) {}; + section_critique(); + in2=false; + // ... + } + + .. comment:: + + Cette solution ne fonctionne pas. Il est possible que le thread 1 rentre en section critique puis le thread 2 met ``last`` à 2 et peut également y entrer sans que thread 1 n'en soit sorti. + + .. negative:: + + .. code-block:: c + + // initialisation + bool in1 = false; + bool in2 = false; + int last = 1; + // thread 1 + while (true) { + last = 1; + in1 = true; + while ( in2 && (last==1)) {}; + section_critique(); + in1=false; + // ... + } + // thread2 + while (true) { + last = 2; + in2 = true; + while ( in1 && (last==2)) {}; + section_critique(); + in2=false; + // ... + } + + .. comment:: + + Cette solution ne fonctionne pas. Il y a un risque de violation de section critique. Si le thread 1 fait ``last=1;`` puis est interrompu avant de faire ``in1=true;``. Le thread 2 exécute alors ``last=2;`` suivi de ``in2=true;``. A cet instant, ``in2==false`` et le thread 2 rentre en section critique puisque ``in1==false``. Le thread 1 se réveille et exécute ``in1=true;``. Il peut ensuite immédiatement entre en section critique puisque ``last`` vaut ``2`` à cet instant. + +Question 4. Initialisation de mutex +----------------------------------- + +.. question:: mutexinit + :nb_prop: 3 + :nb_pos: 1 + + Avant de pouvoir utiliser un mutex POSIX, il est nécessaire de déclarer la structure correspondante et initialiser le mutex. Parmi les fragments de code ci-dessous, lequel est celui qui déclare et initialise correctement un mutex ? + + .. positive:: + + .. code-block:: c + + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + err= pthread_mutexattr_init(&attr); + if(err!=0) + error(err,"pthread_mutexattr_init"); + + err=pthread_mutex_init( &mutex, &attr); + if(err!=0) + error(err,"pthread_mutex_init"); + + .. comment:: + + Notez que dans ce cas, le mutex est initialisé avec les attributs par défaut. + + + .. positive:: + + .. code-block:: c + + pthread_mutex_t mutex; + + err=pthread_mutex_init( &mutex, NULL); + if(err!=0) + error(err,"pthread_mutex_init"); + + .. comment:: + + Notez que dans ce cas, le mutex est initialisé avec les attributs par défaut. + + .. negative:: + + + .. code-block:: c + + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + err= pthread_mutexattr_init(attr); + if(err!=0) + error(err,"pthread_mutexattr_init"); + + err=pthread_mutex_init(mutex, attr); + if(err!=0) + error(err,"pthread_mutex_init"); + + .. comment:: Tant `pthread_mutexattr_init(3posix)`_ que `pthread_mutex_init(3posix)`_ prennent comme arguments un *pointeur* vers une structure de type ``pthread_mutex_t``. Ces deux fonctions modifient le contenu de cette structure et doivent donc en recevoir l'adresse comme argument. + + + .. negative:: + + .. code-block:: c + + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + err= pthread_mutexattr_init(&attr); + if(err!=0) + error(err,"pthread_mutexattr_init"); + + err=pthread_mutex_init(&mutex, attr); + if(err!=0) + error(err,"pthread_mutex_init"); + + .. comment:: Tant `pthread_mutexattr_init(3posix)`_ que `pthread_mutex_init(3posix)`_ prennent comme arguments un *pointeur* vers une structure de type ``pthread_mutex_t``. Ces deux fonctions modifient le contenu de cette structure et doivent donc en recevoir l'adresse comme argument. + + + .. negative:: + + .. code-block:: c + + pthread_mutex_t *mutex; + pthread_mutexattr_t *attr; + + err= pthread_mutexattr_init(attr); + if(err!=0) + error(err,"pthread_attr_init"); + + err=pthread_mutex_init(mutex, attr); + if(err!=0) + error(err,"pthread_mutex_init"); + + .. comment:: Tant `pthread_mutexattr_init(3posix)`_ que `pthread_mutex_init(3posix)`_ prennent comme arguments un *pointeur* vers une structure de type ``pthread_mutex_t``. La mémoire permettant de stocker ces deux structures doit avoir été réservée en utilisant `malloc(3)`_ avant de faire appel à ces deux fonctions. + + + +Question 5. Utilisation de `pthread_mutex_lock(3posix)`_ et `pthread_mutex_unlock(3posix)`_ +------------------------------------------------------------------------------------------- + +.. question:: pthread_mutex_lock + :nb_prop: 3 + :nb_pos: 1 + + Un programme utilisant plusieurs threads doit mettre à jour une variable globale partagée entre tous les threads. Pour cela, le développeur écrit une fonction ``update`` qui prend comme arguments la variable à mettre à jour et le mutex qui y est associé. Parmi les extraits ci-dessous, lequel permet de mettre à jour la variable sans risque de contention entre les threads qui y accèdent ? + + .. positive:: + + + .. code-block:: c + + void update(int * val, pthread_mutex_t * mutex) { + + err=pthread_mutex_lock(mutex); + if(err!=0) + error(err,"pthread_mutex_lock"); + + // mise à jour de la variable globale + + err=pthread_mutex_unlock(mutex); + if(err!=0) + error(err,"pthread_mutex_unlock"); + + } + + + .. negative:: + + + .. code-block:: c + + void update(int * val, pthread_mutex_t * mutex) { + + err=pthread_mutex_unlock(mutex); + if(err!=0) + error(err,"pthread_mutex_unlock"); + + // mise à jour de la variable globale + + err=pthread_mutex_lock(mutex); + if(err!=0) + error(err,"pthread_mutex_lock"); + + } + + .. comment:: Ce code est incorrect. Un mutex s'utilise en faisant d'abord ``pthread_mutex_lock`` et ensuite ``pthread_mutex_unlock``. + + .. negative:: + + .. code-block:: c + + void update(int val, pthread_mutex_t mutex) { + + err=pthread_mutex_lock(mutex); + if(err!=0) + error(err,"pthread_mutex_lock"); + + // mise à jour de la variable globale + + err=pthread_mutex_unlock(mutex); + if(err!=0) + error(err,"pthread_mutex_unlock"); + + } + + .. comment:: L'utilisation de cette fonction implique que la structure ``pthread_mutex_t`` doit être copiée sur le stack avant de pouvoir être utilisée par la fonction. Cette solution ne peut fonctionner car la structure de données qui contient toute l'information relative à un mutex et placée à un endroit donné en mémoire et ne peut pas être copiée. + + + .. negative:: + + .. code-block:: c + + void update(int * val, pthread_mutex_t mutex) { + + err=pthread_mutex_lock(&mutex); + if(err!=0) + error(err,"pthread_mutex_lock"); + + // mise à jour de la variable globale + + err=pthread_mutex_unlock(&mutex); + if(err!=0) + error(err,"pthread_mutex_unlock"); + + } + + .. comment:: L'utilisation de cette fonction implique que la structure ``pthread_mutex_t`` doit être copiée sur le stack avant de pouvoir être utilisée par la fonction. Cette solution ne peut fonctionner car la structure de données qui contient toute l'information relative à un mutex et placée à un endroit donné en mémoire et ne peut pas être copiée. + + + +Question 6. Utilisation de plusieurs mutex +------------------------------------------ + + + +Dans certains programmes, il est nécessaire de définir plusieurs mutex qui sont utilisés par différents threads pour gérer l'accès à des variables partagées. Considérons un programme qui utilise trois variables globales et est découpé en plusieurs threads. + +.. code-block:: c + + long a=5; // variable globale partagée + long b=7; // variable globale partagée + long c=9; // variable globale partagée + + pthread_mutex_t x; // variable globale associée à a + pthread_mutex_t y; // variable globale associée à b + pthread_mutex_t z; // variable globale associée à c + + + void update(int * val1, int * val2, pthread_mutex_t * mutex1, pthread_mutex_t * mutex2) { + + err=pthread_mutex_lock(mutex1); + if(err!=0) + error(err,"pthread_mutex_lock"); + err=pthread_mutex_lock(mutex2); + if(err!=0) + error(err,"pthread_mutex_lock"); + + // mise à jour val1 + // mise à jour val2 + + err=pthread_mutex_unlock(mutex1); + if(err!=0) + error(err,"pthread_mutex_unlock"); + + err=pthread_mutex_unlock(mutex2); + if(err!=0) + error(err,"pthread_mutex_unlock"); + + } + +.. question:: plusieursmutex + :nb_prop: 3 + :nb_pos: 1 + + Ce programme utilise plusieurs threads qui modifient les variables ``a``, ``b`` et ``c``. Parmi les fragments de code ci-dessous qui utilisent plusieurs threads, un seul est correct. Lequel ? + + .. positive:: + + + .. code-block:: c + + // thread A + + update(&a,&b,&x,&y); + update(&a,&c,&x,&z); + + // thread B + + update(&b,&c,&y,&z); + update(&a,&c,&x,&z); + + + .. positive:: + + .. code-block:: c + + // thread A + + update(&a,&b,&x,&y); + update(&b,&c,&y,&z); + + // thread B + + update(&b,&c,&y,&z); + update(&a,&c,&x,&z); + + + .. negative:: + + + .. code-block:: c + + // thread A + + update(&a,&b,&x,&y); + update(&c,&a,&z,&x); + + // thread B + + update(&b,&c,&y,&z); + update(&a,&c,&x,&z); + + .. comment:: Lorsqu'un thread utilise plusieurs ressources protégées par un mutex, il est important que les accès à ces mutex se fasse chaque fois dans le même ordre. Dans cet exemple, il faut toujours accéder à ``x`` puis à ``y`` puis à ``z`` (ou un autre ordre). Accéder à ``z`` puis à ``x`` dans le thread A et à ``x`` puis à ``z`` dans le thread B est une source de deadlocks potentiels. + + .. negative:: + + .. code-block:: none + + // thread A + + update(&a,&b,&x,&y); + update(&a,&c,&x,&z); + + // thread B + + update(&b,&c,&y,&z); + update(&c,&a,&z,&x); + + .. comment:: Lorsqu'un thread utilise plusieurs ressources protégées par un mutex, il est important que les accès à ces mutex se fasse chaque fois dans le même ordre. Dans cet exemple, il faut toujours accéder à ``x`` puis à ``y`` puis à ``z`` (ou un autre ordre). Accéder à ``z`` puis à ``x`` dans le thread B et à ``x`` puis à ``z`` dans le thread A est une source de deadlocks potentiels. + + .. negative:: + + .. code-block:: c + + // thread A + + update(&a,&b,&x,&y); + update(&a,&b,&x,&y); + + // thread B + + update(&b,&a,&y,&x); + update(&a,&c,&x,&z); + + .. comment:: Lorsqu'un thread utilise plusieurs ressources protégées par un mutex, il est important que les accès à ces mutex se fasse chaque fois dans le même ordre. Dans cet exemple, il faut toujours accéder à ``x`` puis à ``y`` puis à ``z`` (ou un autre ordre). Accéder à ``a`` puis à ``y`` dans le thread A et à ``y`` puis à ``x`` dans le thread B est une source de deadlocks potentiels. + diff --git a/Exercices/mcq-ex/qcm-7.rst b/Exercices/mcq-ex/qcm-7.rst index 4bc6fa4b31b14d81a61d64e7489839c1af3b6db8..0aeb7fb1a6821fab0e1457aa92ca649bea2e17c1 100644 --- a/Exercices/mcq-ex/qcm-7.rst +++ b/Exercices/mcq-ex/qcm-7.rst @@ -103,7 +103,7 @@ Question 1. Utilisation des sémaphores .. negative:: - .. code-block:: c + .. code-block:: none sem_t *semaphore; semaphore=(sem_t *)malloc(sizeof(struct sem_t)); @@ -443,7 +443,3 @@ Question 3. Fonctions 'thread-safe' Les fonctions qui ne sont pas thread-safe sont listées dans `pthreads(7)`_. - -.. include:: ../../links.rst -.. include:: ../../man_links.rst -.. include:: ../../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-8.rst b/Exercices/mcq-ex/qcm-8.rst index 40b40bd2950a9540883e6cc40faecc75187140f7..c0eb19846a866bab4529a0e7ca67b15caf699200 100644 --- a/Exercices/mcq-ex/qcm-8.rst +++ b/Exercices/mcq-ex/qcm-8.rst @@ -49,49 +49,49 @@ L'appel système `fork(2)`_ permet de créer une copie du processus courant. Un Lorsque ``n`` est initialisé à ``2``, quatre processus sont créés. - .. comment:: + .. comment:: - Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Ces deux processus exécutent à leur tour `fork(2)`_ et deux processus supplémentaires sont donc créés. + Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Ces deux processus exécutent à leur tour `fork(2)`_ et deux processus supplémentaires sont donc créés. .. positive:: Lorsque ``n`` est initialisé à ``3``, huit processus sont créés. - .. comment:: + .. comment:: - Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Ces deux processus exécutent à leur tour `fork(2)`_ et deux processus supplémentaires sont donc créés. Chacun de ces quatre processus exécute à son tour `fork(2)`_ et il y a donc huit processus au total. + Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Ces deux processus exécutent à leur tour `fork(2)`_ et deux processus supplémentaires sont donc créés. Chacun de ces quatre processus exécute à son tour `fork(2)`_ et il y a donc huit processus au total. .. negative:: Lorsque ``n`` est initialisé à ``2``, deux processus sont créés. - .. comment:: + .. comment:: - Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. + Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. .. negative:: Lorsque ``n`` est initialisé à ``2``, trois processus sont créés. - .. comment:: + .. comment:: - Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. + Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. .. negative:: Lorsque ``n`` est initialisé à ``3``, trois processus sont créés. - .. comment:: + .. comment:: - Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. + Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. .. negative:: Lorsque ``n`` est initialisé à ``3``, quatre processus sont créés. - .. comment:: + .. comment:: - Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. + Le premier processus démarre son exécution. Il exécute `fork(2)`_. Un nouveau processus est donc créé. Chacun de ces deux processus poursuit son exécution et la valeur de ``i`` est incrémentée. Question 2. `execve(2)`_ ------------------------ @@ -486,7 +486,3 @@ Question 5. Récupération du résultat d'un processus avec `waitpid(2)`_ La valeur de retour de `waitpid(2)`_ indique si l'appel système s'est exécuté correctement ou non. Pour récupérer le statut du processus fils ``pid``, il faut utiliser la macro ``WEXITSTATUS``. Le pointeur ``int * status`` doit pointer vers une zone mémoire allouée par malloc. Ici, il pointe vers ``NULL``. - -.. include:: ../../links.rst -.. include:: ../../man_links.rst -.. include:: ../../incl_links.rst diff --git a/Exercices/mcq-ex/qcm-9.rst b/Exercices/mcq-ex/qcm-9.rst index f0499ed9e77513d0fa26e98256d5e75a2c2c9c60..c6ccfa12d1d03ffd564404bb392a014f4c71d6c5 100644 --- a/Exercices/mcq-ex/qcm-9.rst +++ b/Exercices/mcq-ex/qcm-9.rst @@ -532,7 +532,3 @@ Considérons un répertoire dans lequel les commandes suivantes sont exécutées - les fichiers ``a`` et ``c`` ont la même taille - l'`inode` correspondant au fichier ``a`` indique qu'il y a deux liens vers lui - -.. include:: ../../links.rst -.. include:: ../../man_links.rst -.. include:: ../../incl_links.rst diff --git a/Exercices/mcq-ex/revision.rst b/Exercices/mcq-ex/revision.rst.old similarity index 100% rename from Exercices/mcq-ex/revision.rst rename to Exercices/mcq-ex/revision.rst.old diff --git a/Outils/_static b/Outils/_static new file mode 120000 index 0000000000000000000000000000000000000000..7a2b653646f86d98f976df94c66c017b5d24ecbe --- /dev/null +++ b/Outils/_static @@ -0,0 +1 @@ +../_static \ No newline at end of file diff --git a/Outils/_templates b/Outils/_templates new file mode 120000 index 0000000000000000000000000000000000000000..db3df549a44959a192630b263daa927927264ea8 --- /dev/null +++ b/Outils/_templates @@ -0,0 +1 @@ +../_templates \ No newline at end of file diff --git a/Outils/bib.rst b/Outils/bib.rst new file mode 100644 index 0000000000000000000000000000000000000000..f011349ece0bef62bb87889e6dfd7ef88ef23395 --- /dev/null +++ b/Outils/bib.rst @@ -0,0 +1,18 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + +************* +Bibliographie +************* + + +.. [DeveloppezMake] Introduction à Makefile, http://gl.developpez.com/tutoriel/outil/makefile/ + + +.. [GNUMake] The GNU Make Manual, http://www.gnu.org/software/make/manual/make.html + + + +.. [Honeyford2006] Honeyford, M., `Speed your code with the GNU profiler`, http://www.ibm.com/developerworks/library/l-gnuprof.html + diff --git a/Outils/conf.py b/Outils/conf.py index 7badad42d15b04b9acce87d155b5dfe11dd4f773..7a9e81ee239169140d54a09166c62e63a9c2e7ee 100644 --- a/Outils/conf.py +++ b/Outils/conf.py @@ -103,7 +103,7 @@ rst_epilog = """ .. include:: /../Theorie/incl_links.rst """ # Intersphinx -intersphinx_mapping = {'theorie': ('http://sites.uclouvain.be/SystInfo/notes/Theorie/html/', None), 'outils': ('http://sites.uclouvain.be/SystInfo/notes/Outils/html/', None), 'exercices': ('http://sites.uclouvain.be/SystInfo/notes/Exercices/html/', None)} +intersphinx_mapping = {'theorie': ('https://sites.uclouvain.be/SystInfo/notes/Theorie/html/', None), 'outils': ('https://sites.uclouvain.be/SystInfo/notes/Outils/html/', None), 'exercices': ('https://sites.uclouvain.be/SystInfo/notes/Exercices/html/', None)} diff --git a/Outils/cunit.rst b/Outils/cunit.rst index 418f6a75f8ab18676fb5780765522d124c7be4df..9c1c48d4b0a40e0317ea96a7e5c8e6162dce6b9c 100644 --- a/Outils/cunit.rst +++ b/Outils/cunit.rst @@ -47,7 +47,7 @@ Compilation, édition des liens et exécution Comme la librairie n'est pas installée dans les chemins classiques, il faut pouvoir dire à gcc où se trouvent les fichiers d'entête ainsi que la librairie afin d'éviter les erreurs de compilation. Pour cela, il faut spécifier à la -compilation l'argument ``-I$(HOME)/local/include`` afin de lui dire qu'il doit +compilation l'argument ``-I${HOME}/local/include`` afin de lui dire qu'il doit également aller chercher des fichiers d'entête dans le dossier ``$HOME/local/include`` en plus des chemins classiques tels que ``/usr/include`` et ``/usr/local/include``. @@ -55,7 +55,7 @@ compilation l'argument ``-I$(HOME)/local/include`` afin de lui dire qu'il doit Lors de l'édition des liens avec le linker, il faut spécifier où se trouve la librairie dynamique afin de résoudre les symboles. Pour cela, il faut passer l'argument ``-lcunit`` pour effectuer la liaison avec la librairie CUnit ainsi -que lui spécifier ``-L$(HOME)/local/lib`` afin qu'il cherche également des +que lui spécifier ``-L${HOME}/local/lib`` afin qu'il cherche également des librairies dans le dossier ``$HOME/local/lib``. Lors de l'exécution, il faut également spécifier où se trouvent les diff --git a/Outils/gdb.rst b/Outils/gdb.rst index dedd25c588fc5686bc39bb5a8bce0b879ac6ad67..04a8df09f3f5f891e268516ea5d750667626a454 100644 --- a/Outils/gdb.rst +++ b/Outils/gdb.rst @@ -18,62 +18,61 @@ Liste des commandes L'option -g de `gcc(1)`_ place dans l'exécutable les informations sur les noms de variables, mais aussi tout le code source. - -Lancez gdb avec la commande ``gdb my_program``. Ceci va vous ouvrir la console de gdb qui vous permet de lancer, le programme et de l'analyser. Pour démarrer le programme, tapez ``run``. gdb va arrêter l'exécution au premier problème trouvé. Votre programme tourne encore pour l'instant. Arrètez-le avec la commande ``kill``. +Lancez gdb avec la commande ``gdb my_program``. Ceci va vous ouvrir la console de ``gdb`` qui vous permet de lancer, le programme et de l'analyser. Pour démarrer le programme, tapez ``run``. gdb va arrêter l'exécution au premier problème trouvé. Votre programme tourne encore pour l'instant. Arrètez-le avec la commande ``kill``. Breakpoint ^^^^^^^^^^ Pour analyser un programme, vous pouvez y placer des breakpoints. Un breakpoint permet de mettre en pause l'exécution d'un programme à un endroit donné pour pouvoir afficher l'état des variables et faire une exécution pas-à -pas. Pour mettre un breakpoint, vous avez plusieurs choix: - - * ``break [function]`` met en pause l'exécution à l'appel de la fonction passée en argument à la commande + + * ``break [function]`` met en pause l'exécution à l'appel de la fonction passée en argument à la commande * ``break [filename:linenumber]`` spécifie le fichier du code source et la ligne à laquelle l'exécution doit s'arrêter * ``delete [numberbreakpoint]`` supprime le breakpoint spécifié - Note : Chaque breakpoint est caractérisé par un numéro. Pour obtenir la liste des breakpoints utilisé ``info break`` + Note : Chaque breakpoint est caractérisé par un numéro. Pour obtenir la liste des breakpoints utilisés ``info break`` Informations à extraire ^^^^^^^^^^^^^^^^^^^^^^^ -Une fois un breakpoint placé, plusieurs informations peuvent être extraites via `gdb(1)`_ : - - * ``print [variablename]`` affiche la valeur de la variable dans son format de base. Il est possible de connaitre la valeur pointé en utilisant ``*`` ainsi que l'adresse de la variable avec ``&``. +Une fois un breakpoint placé, plusieurs informations peuvent être extraites via `gdb(1)`_ : + + * ``print [variablename]`` affiche la valeur de la variable dans son format de base. Il est possible de connaître la valeur pointée en utilisant ``*`` ainsi que l'adresse de la variable avec ``&``. .. code-block:: console - + Il est aussi possible de modifier une variable avec ``set variable [nom_variable] = [valeur]``. De façon similaire avec ``print [nom_variable] = [valeur]``. - - * ``info reg [registre]`` affiche les informations sur tout les registres si aucun registre n'est explicitement spécifié. ``info reg eax`` donne le même résultat que ``print $eax``. + + * ``info reg [registre]`` affiche les informations sur tous les registres si aucun registre n'est explicitement spécifié. ``info reg eax`` donne le même résultat que ``print $eax``. .. code-block:: console - Il est interressant de noter qu'il est possible d'afficher la variable sous le format spécifié. Pour cela, remplacer ``print`` par : + Il est intéressant de noter qu'il est possible d'afficher une variable sous le format spécifié. Pour cela, remplacer ``print`` par : * ``p/x`` - affiche en format hexadécimal la variable spécifiée - * ``p/d`` - en format d'un entier signé + * ``p/d`` - en format entier signé * ``p/f`` - en format floating point * ``p/c`` - affiche un caractère. - * ``backtrace`` ou ``bt`` affiche la pile des appels de fonctions. - + * ``backtrace`` ou ``bt`` affiche la pile des appels de fonctions. + .. code-block:: console - Il est possible de naviguer dans la pile des appels à l'aide de ``up`` et ``down``. Ces deux commandes montent et descendent respectivement dans la pile. Cela est très utile car il permet de modifier le contexte dans lequel on se trouve pour afficher les variables. + Il est possible de naviguer dans la pile des appels à l'aide de ``up`` et ``down``. Ces deux commandes montent et descendent respectivement dans la pile. C'est très utile car il est possible de modifier le contexte dans lequel on se trouve pour afficher les variables. * ``info frame`` donne des informations sur la frame actuelle. * ``list`` affiche les lignes de codes entourant le break. On peut donc facilement voir le code posant un problème ou analyser le code avant de faire une avancée pas à pas. - * ``show args`` affiche les arguments passé au programme. + * ``show args`` affiche les arguments passés au programme. * ``info breakpoints`` affiche les breakpoints * ``info diplays`` affiche les displays * ``info func [fonctionname]`` affiche le prototype d'une fonction -Avancement de l'execution +Avancement de l'exécution ^^^^^^^^^^^^^^^^^^^^^^^^^ -Quand vous avez acquis suffisament d'informations sur le programme, vous avez plusieurs choix pour continuer l'exécution : - +Quand vous avez acquis suffisamment d'informations sur le programme, vous avez plusieurs choix pour continuer son exécution : + * ``next`` exécute la prochaine instruction de votre code source, mais sans rentrer dans des fonctions externes. * ``step`` exécute la prochaine instruction de votre code source, mais en entrant dans le code des fonctions appelées. * ``continue`` continue le reste de l'exécution jusqu'au prochain breakpoint. @@ -81,24 +80,24 @@ Quand vous avez acquis suffisament d'informations sur le programme, vous avez pl Automatisation ^^^^^^^^^^^^^^ -Lors d'un débuggage long et fastidieux, il est parfois indispensable d'effectuer certaines commandes à chaque breakpoint. +Lors d'un débuggage long et fastidieux, il est parfois nécessaire d'exécuter certaines commandes à chaque breakpoint. - * ``commands [numerobreakpoint]`` definit une liste de commande associé à un breakpoint. Celles ci seront exécutées quand on s'arretera sur ce breakpoint. Il suffit de taper les commandes à effectuer les unes après les autres et de terminer par ``end``. Si vous ne fournissez pas de numero, les commandes sont assigné au dernier break point créé. + * ``commands [numerobreakpoint]`` definit une liste de commandes associées à un breakpoint. Celles ci seront exécutées quand on s'arrêtera sur ce breakpoint. Il suffit de taper les commandes à effectuer les unes après les autres et de terminer par ``end``. Si vous ne fournissez pas de numéro, les commandes sont assignées au dernier breakpoint créé. * ``display [variablename]`` affiche la variable à chaque breakpoint. Gestion des Signaux ^^^^^^^^^^^^^^^^^^^ -En plus des breakpoints, `gdb(1)`_ interrompt l'exécution du programme en cours lorsqu'il intercepte certains signaux d'erreurs comme les signaux ``SIGSEGV`` et ``SIGINT``. `gdb(1)`_ permettra alors de corriger plus facilement certaines erreurs comme les erreurs de segmentation ou les problèmes de deadlock. +En plus des breakpoints, `gdb(1)`_ interrompt l'exécution du programme en cours lorsqu'il intercepte certains signaux d'erreurs comme les signaux ``SIGSEGV`` et ``SIGINT``. `gdb(1)`_ permettra alors de corriger plus facilement certaines erreurs comme les erreurs de segmentation ou les problèmes de deadlocks. Il est possible de gérer le comportement de `gdb(1)`_ lorsque des signaux sont interceptés. Tout d'abord, la commande ``info signals`` permet d'afficher la liste des signaux reconnus par `gdb(1)`_ ainsi que la façon dont il les traite (par exemple interrompre le programme en cours ou non). On peut changer la façon de traiter un signal avec la commande ``handle [SIGNAL] [HANDLING...]`` où ``[SIGNAL]`` est le signal à intercepter (son numéro ou son nom complet) et ``[HANDLING]`` la façon de traiter ce signal par `gdb(1)`_ [#fSigList]_. Par exemple, la commande ``handle SIGALRM stop print`` permet d'interrompre le programme et d'afficher un message quand gdb intercepte le signal ``SIGALRM``. Localiser un signal """"""""""""""""""" -Avec `gdb(1)`_, il est donc possible de localiser un signal et de débugguer certaines erreurs comme une erreur de segmentation. En effet, lorsque `gdb(1)`_ interrompt le programme en cours après l'interception d'un signal d'erreur comme ``SIGSEGV``, il est possible de trouver la ligne du programme à laquelle le signal a été intercepté en tapant le mot-clé ``where`` une fois le programme interrompu (il est cependant important d'avoir compilé le programme avec l'option ``-g`` de ``gcc`` pour trouver la ligne précise). Ensuite, grâce aux commandes expliquées plus tôt, il sera possible de vérifier les valeurs des variables lors de l'interception du signal pour trouver l'origine du problème. +Avec `gdb(1)`_, il est possible de localiser un signal et de débugguer certaines erreurs comme une erreur de segmentation. En effet, lorsque `gdb(1)`_ interrompt le programme en cours après l'interception d'un signal d'erreur comme ``SIGSEGV``, il est possible de trouver la ligne du programme à laquelle le signal a été intercepté en tapant le mot-clé ``where`` une fois le programme interrompu (il est cependant nécessaire d'avoir compilé le programme avec l'option ``-g`` de ``gcc`` pour trouver la ligne précise). Ensuite, grâce aux commandes expliquées plus tôt, il est possible de vérifier les valeurs des variables lors de l'interception du signal pour trouver l'origine du problème. -En plus de localiser facilement les erreurs de segmentation dans un programme, vous pourrez régler plus aisément les problèmes de deadlock des threads. En effet, lorsque le programme est lancé sur le shell et que vous remarquez un deadlock, vous pouvez appuyer sur ``CTRL + C`` pour lancer le signal ``SIGINT`` au programme. Cela permettra de trouver les endroits où bloquent les différents threads du programme à l'aide des commandes décrites dans la section de débuggage des threads ci-dessous. +En plus de localiser facilement les erreurs de segmentation dans un programme, vous pourrez annalyser plus aisément les problèmes de deadlock des threads. En effet, lorsque le programme est lancé sur le shell et que vous remarquez un deadlock, vous pouvez appuyer sur ``CTRL + C`` pour lancer le signal ``SIGINT`` au programme. Cela permettra de trouver les endroits où bloquent les différents threads du programme à l'aide des commandes décrites dans la section de débuggage des threads ci-dessous. Extraction de code assembleur ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,12 +111,12 @@ Pour arrêter la console de gdb, tappez ``quit``. Illustration avec des exemples ------------------------------ -A titre d'exemple, telecharger cette archive :download:`src/gdb.c`. L'archive contient un Makefile qui vous permettra de compiler plusieurs programmes. +.. A titre d'exemple, télécharger l'archive :download:`src/gdb.c`. L'archive contient un Makefile qui vous permettra de compiler plusieurs programmes. Premier programme ^^^^^^^^^^^^^^^^^ - Le premier programme est ``calc``. Executez le pour vous apercevoir que le programme bug. A priori peu, ou pas, d'information sur l'erreur. Lancez donc gdb à l'aide de ``gdb calc`` puis lancez le programme avec ``run``. + Le premier programme est :download:`src/calc.c`. Compilez-le et exécutez le pour vous apercevoir que le programme est erroné. A priori vous avez peu, ou pas, d'informations sur l'erreur. Lancez donc gdb à l'aide de ``gdb calc`` puis lancez le programme avec ``run``. .. code-block:: console @@ -126,15 +125,19 @@ Premier programme 10 res = (a*5 -10) / (b-i); => Affichage de la ligne problématique - Le premier réflexe doit être ``list`` pour observer le code. Puisque le problème vient de la ligne 10 dans la boucle, nous allons nous arreter à la ligne 10 avec ``break 10`` et relancer le programme. - Le programme va s'arrêter avant le début de la boucle. ``print a`` et ``print b`` pour connaitre les arguments reçus par calc. - - .. code-block:: console + Le premier réflexe doit être ``list`` pour observer le code. Puisque le problème vient de la ligne 10 dans la boucle, nous allons nous arrêter à la ligne 10 avec ``break 10`` et relancer le programme. + Le programme va s'arrêter avant le début de la boucle. Utilisez ``print a`` et ``print b`` pour connaître les arguments reçus par calc. + + .. code-block:: console - Il est interressant de noter une particularité du language C par rapport à java : une variable déclaré n'est pas initialisé à 0 par défault, elle reprend juste la valeur de la mémoire avant son affectation. ``print i`` et ``print res`` vous donnerons donc des résultats aléatoires. - - Puisque le problème vient du calcul arithmetique, placez un break sur cette ligne pour pouvoir observer à chaque itération les variables. ``break 9`` puis ``commands`` qui permet d'automatiser des commandes. Nous rajouterons comme commandes : + Il est intéressant de noter une particularité du language C par rapport à java : une variable déclarée n'est pas initialisée à 0 par défaut, elle reprend juste la valeur de la mémoire avant son affectation. ``print i`` et ``print res`` vous donneront donc des résultats aléatoires. + + + Puisque le problème vient du calcul arithmétique, placez un break sur cette ligne pour pouvoir observer à chaque itération les variables. ``break 9`` puis ``commands`` qui permet d'automatiser des commandes. Nous rajouterons comme commandes : + + .. code-block:: none + * ``echo i : `` * ``print i`` * ``echo b : `` @@ -143,29 +146,29 @@ Premier programme * ``print a*5 -10`` * ``echo denominateur : `` * ``print b-i`` - * et enfin ``end`` pour terminer la liste de commandeq. - + * et enfin ``end`` pour terminer la liste de commandes. + Il ne reste plus qu'à avancer avec ``continue`` pour aller de breakpoint en breakpoint et d'observer les variables pour comprendre le problème. On va pouvoir deviner que le problème vient d'un dénominateur nul. Pour résoudre ce problème, il faut passer une valeur plus grande que 6 à calc lors de son appel depuis la fonction main. ``list main`` suivi de plusieurs ``list`` permet de visualiser la main. On peut repérer l'appel de la fonction calc à la ligne 18. - + Supprimez les anciens break avec ``delete [numerobreakpoint]`` le numéro du breakpoint est connu via ``info break``. Rajoutez un break à la ligne 18, ``break 18`` et lancez le programme. ``set variable m = 10`` pour assigner la valeur 10 à la variable m. Puis continuez l'exécution du programme. Celui se terminera normalement puisque il n'y a plus de division par zéro. -Deuxieme programme +Deuxième programme ^^^^^^^^^^^^^^^^^^ - Le deuxieme programme est ``recursive``. Celui ne présente aucun bug et se déroulera normalement. Toutefois, il est interressant d'utiliser `gdb(1)`_ pour bien comprendre les différents contextes au sein d'un programme. Mettez un break sur la fonction factTmp avec ``break factTmp`` et ajoutez automatiquement à ce breakpoint la commande ``backtrace``, via ``commands``. Ensuite, lancez le programme. - ``backtrace`` pour visualiser les appels de fonction effectuées. Nous pouvons voir que la fonction factTmp a été appellé par factTerminal, elle même appellé par la fonction main. + Le deuxième programme est appelé :download:`src/recursive.c`. Celui ne présente aucun bug et se déroulera normalement. Toutefois, il est intéressant d'utiliser `gdb(1)`_ pour bien comprendre les différents contextes au sein d'un programme. Mettez un break sur la fonction factTmp avec ``break factTmp`` et ajoutez automatiquement à ce breakpoint la commande ``backtrace``, via ``commands``. Ensuite, lancez le programme. + ``backtrace`` vous permet de visualiser les appels de fonction effectués. Nous pouvons voir que la fonction factTmp a été appellée par factTerminal, elle même appellée par la fonction main. .. code-block:: console - + #0 factTmp (acc=1, nbr=6) at recursive.c:8 #1 0x000000000040057d in factTerminal (a=6) at recursive.c:17 #2 0x0000000000400598 in main (argc=1, argv=0x7fffffffe1b8) at recursive.c:23 - Essayez d'afficher la variable ``globalVar`` puis ``localVar``. Vous remarquerez qu'il n'est pas possible d'afficher ``localVar`` puisque cette variable puisqu'elle ne fait pas partie de l'environement contextuel de factTmp. Pour afficher cette variable, il faut remonter la liste des appels. ``up`` permettra de remonter les appels pour pouvoir afficher ``localVar``. - Une fois la variable affiché, redescendez avec ``down`` et continuez 4 fois le programme apres le breakpoint. Vous remarquerez que la liste des appels s'allongent à chaque appel récursif, ce qui est tout à fait normal. + Essayez d'afficher les variable ``globalVar`` puis ``localVar``. Vous remarquerez qu'il n'est pas possible d'afficher ``localVar`` puisque cette variable ne fait pas partie de l'environement contextuel de factTmp. Pour afficher cette variable, il faut remonter la liste des appels. ``up`` permettra de remonter les appels pour pouvoir afficher ``localVar``. + Une fois la variable affichée, redescendez avec ``down`` et continuez 4 fois le programme après le breakpoint. Vous remarquerez que la liste des appels s'allonge à chaque appel récursif, ce qui est tout à fait normal. -Naviguez dans les appels recursif de factTmp en affichant les valeur de ``globalTmp``, ``tmp``, ``acc`` et ``nbr``. Il est important de bien comprendre que la variable statique ``globalTmp`` est commune à tout les appels de la fonction ``factTmp`` et un changement de cette variable dans un des appels recursifs modifie la variable des autres appels. A contrario, la variable local ainsi que les arguments sont propre à chaque appels. + Naviguez dans les appels recursifs de factTmp en affichant les valeur de ``globalTmp``, ``tmp``, ``acc`` et ``nbr``. Il est important de bien comprendre que la variable statique ``globalTmp`` est commune à tous les appels de la fonction ``factTmp`` et un changement de cette variable dans un des appels récursifs modifie la variable des autres appels. A contrario, la variable local ainsi que les arguments sont propres à chaque appel. Vous pouvez maintenant terminer le programme. @@ -173,11 +176,11 @@ Naviguez dans les appels recursif de factTmp en affichant les valeur de ``global Troisième programme ^^^^^^^^^^^^^^^^^^^ - Le troisième programme est ``tab``. Ce programme s'exécute correctement, et pourtant, il y a une erreur. Lancez le programme avec gsb et mettez un breakpoint sur la première instruction, à savoir la ligne 9. Pour comprendre un problème sans savoir où commencer, il est utile de suivre l'évolution des variables. + Le troisième programme est :download:`src/tab.c`. Compilez-le. Ce programme s'exécute correctement, et pourtant, il y contient une erreur. Lancez le programme avec gdb et mettez un breakpoint sur la première instruction, à savoir la ligne 9. Pour comprendre un problème sans savoir où commencer, il est utile de suivre l'évolution des variables. .. code-block:: console - - Il est important de savoir que ``print``, ainsi que ``display``, comprend les expressions telque : + + Il est important de savoir que ``print``, ainsi que ``display``, supportent les expressions telles que : * tab[1], tab[i],... * &i, *i,... @@ -186,7 +189,7 @@ Troisième programme Plus d'informations sur `gdb(1)`_ peuvent être trouvées sur: - + * http://www.cprogramming.com/gdb.html * http://www.ibm.com/developerworks/library/l-gdb/ * https://www.rocq.inria.fr/secret/Anne.Canteaut/COURS_C/gdb.html @@ -197,9 +200,9 @@ Débuggage des threads avec GDB `gdb(1)`_ est aussi utile pour débugger des programmes avec des threads. Il permet de faire les opérations suivantes sur les threads: - * Notifier lors de la création d'un nouveau thread. + * Etre notifié lors de la création d'un nouveau thread. * Afficher la liste complète des threads avec ``info threads``. - * Mettre un breakpoint dans un thread. En effet, si vous placez un breakpoint dans une certaine fonction, et un thread passe lors de son exécution à travers de ce breakpoint, ``gdb`` va mettre l'exécution de tous les threads en pause et changer le contexte de la console `gdb(1)`_ vers ce thread. + * Placer un breakpoint dans un thread. En effet, si vous placez un breakpoint dans une certaine fonction, et un thread passe lors de son exécution à travers ce breakpoint, ``gdb`` va mettre l'exécution de tous les threads en pause et changer le contexte de la console `gdb(1)`_ vers ce thread. * Lorsque les threads sont en pause, vous pouvez manuellement donner la main à un thread en faisant ``thread [thread_no]`` avec ``thread_no`` étant l'indice du thread comme indiqué par ``info threads`` D'autres commandes pour utiliser `gdb(1)`_ avec les threads: diff --git a/Outils/git.rst b/Outils/git.rst index 03027021b35791e8f81595c9e64e3727cbf9589d..43ae7eac4a41756e81336553c61e755c73655568 100644 --- a/Outils/git.rst +++ b/Outils/git.rst @@ -692,8 +692,8 @@ Une fois vos changements commités, vous pouvez les ajouter à *origin* avec $ git push origin master -Votre amélioration devrait normalement être visible -`ici <https://github.com/obonaventure/SystemesInformatiques/network>`_. +Votre amélioration devrait normalement être visible via +`https://github.com/obonaventure/SystemesInformatiques/network <https://github.com/obonaventure/SystemesInformatiques/network>`_. Vous pouvez maintenant aller sur Github à la page de votre fork et cliquer sur *Pull Requests* puis *New pull request* et expliquer vos changements. @@ -1648,7 +1648,7 @@ Afficher l'historique Pour afficher l'historique, outre l'outil utilisé pour faire les illustrations de ce cours que vous pouvez retrouver -`ici <https://github.com/blegat/git-dot>`_, +`https://github.com/blegat/git-dot <https://github.com/blegat/git-dot>`_, il existe la commande `git-log(1)`_. Elle est très flexible comme on va le voir. ``git log`` affiche simplement l'historique à partir de ``HEAD`` diff --git a/Outils/index.rst b/Outils/index.rst index 4f12fd727bb815b1763de2c74408195e4a5e446a..556a6a3ef219ac4b3e669e9b48d462ee14d72521 100644 --- a/Outils/index.rst +++ b/Outils/index.rst @@ -32,4 +32,5 @@ Systèmes informatiques : Outils gprof shell gcc + bib diff --git a/Outils/intro-outils.rst b/Outils/intro-outils.rst index 461b4c13cc0d4aaf6bdeb720ab446962edfe2d99..244cfd856b3710e6d99e2dd95e562997914a89b6 100644 --- a/Outils/intro-outils.rst +++ b/Outils/intro-outils.rst @@ -42,6 +42,6 @@ Dans de nombreux projets informatiques, il est nécessaire d'utiliser des outils Compilateurs ============ -Le compilateur C utilisé dans de nombreuses distributions Linux est `gcc(1)`_. C'est un compilateur open-source développé activement dans le cadre du projet |gnu| par la `Free Software Foundation <http://www.fsf.org>`_. Nous utiliserons principalement `gcc(1)`_ dans le cadre de ce cours. +Le compilateur C utilisé dans de nombreuses distributions Linux est `gcc(1)`_. C'est un compilateur open-source développé activement dans le cadre du projet GNU par la `Free Software Foundation <http://www.fsf.org>`_. Nous utiliserons principalement `gcc(1)`_ dans le cadre de ce cours. Il existe des alternatives à `gcc(1)`_ comme llvm_ que nous utiliserons lorsque nous analyserons le code assembleur généré par un compilateur C. Les variantes commerciales de Unix utilisent généralement des compilateurs propriétaires, dont par exemple `Oracle Studio <http://www.oracle.com/technetwork/server-storage/solarisstudio/overview/index.html>`_ ou la `suite de compilateurs <http://software.intel.com/en-us/c-compilers>`_ développée par intel_. diff --git a/Outils/links.rst b/Outils/links.rst deleted file mode 100644 index 4b347abb839c72e9f85a61719cb89da0e9c7f706..0000000000000000000000000000000000000000 --- a/Outils/links.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. Links to be included - - - -.. _intel : http://www.intel.com -.. _python : http://www.python.org -.. _perl : http://www.perl.org -.. _Git : http://git-scm.com/ -.. _subversion : http://subversion.apache.org/ -.. _ISO-8859 : http://en.wikipedia.org/wiki/ISO/IEC_8859 -.. _Unicode: http://en.wikipedia.org/wiki/Unicode -.. _Endianness: http://en.wikipedia.org/wiki/Endianness -.. _llvm: http://llvm.org - -.. |fsf| replace:: Free Software Foundation (FSF - http://www.fsf.org) -.. |gnu| replace:: GNU is Not Unix (GNU - http://www.gnu.org) - - - - diff --git a/Outils/processus.rst b/Outils/processus.rst index c22f04d7616040bede1caa8eb3d47774e6948a63..84c3031159555df8eaf9c8b74c79d34f7e0f1977 100644 --- a/Outils/processus.rst +++ b/Outils/processus.rst @@ -5,7 +5,7 @@ Gestion des processus ===================== -Les systèmes d'exploitation de type Unix sont multitâches et multi-utilisateurs. Cela signifie qu'il est possible d'exécuter simultanément plusieurs programmes qui appartiennent potentiellement à différents utilisateurs. Sous Unix, l'unité d'exécution d'un programme est appelée un :term:`processus`. Lorsque vous exécutez un programme C que vous avez compilé depuis la ligne de commande, le shell lance un nouveau :term:`processus`. Chaque processus est identifié par le système d'exploitation via son :term:`pid` ou :term:`process identifier`. Ce :term:`pid` est alloué par le système d'exploitation à de la création du processus. A tout instant, le système d'exploitation maintient une :term:`table des processus` qui contient la liste de tous les processus qui sont en cours d'exécution. Comme nous aurons l'occasion de nous en rendre compte plus tard, cette table contient énormément d'informations qui sont utiles au système. A ce stade, l'information importante qui se trouve dans la table des processus est le :term:`pid` de chaque processus et l'utilisateur qui possède le processus. La commande `ps(1)`_ permet de consulter de façon détaillée la table des processus sur un système Unix. Voici un exemple d'utilisation de cette commande sur un système Linux. +Les systèmes d'exploitation de type Unix sont multitâches et multi-utilisateurs. Cela signifie qu'il est possible d'exécuter simultanément plusieurs programmes qui appartiennent potentiellement à différents utilisateurs. Sous Unix, l'unité d'exécution d'un programme est appelée un :term:`processus`. Lorsque vous exécutez un programme C que vous avez compilé depuis la ligne de commande, le shell lance un nouveau :term:`processus`. Chaque processus est identifié par le système d'exploitation via son :term:`pid` ou :term:`process identifier`. Ce :term:`pid` est alloué par le système d'exploitation au moment de la création du processus. À tout instant, le système d'exploitation maintient une :term:`table des processus` qui contient la liste de tous les processus qui sont en cours d'exécution. Comme nous aurons l'occasion de nous en rendre compte plus tard, cette table contient énormément d'informations qui sont utiles au système. À ce stade, l'information importante qui se trouve dans la table des processus est le :term:`pid` de chaque processus et l'utilisateur qui possède le processus. La commande `ps(1)`_ permet de consulter de façon détaillée la table des processus sur un système Unix. Voici un exemple d'utilisation de cette commande sur un système Linux. .. code-block:: console @@ -21,7 +21,7 @@ Dans cet exemple, l'utilisateur ``obo`` possède actuellement deux processus. Le Pour comprendre le fonctionnement des processus, il est intéressant d'expérimenter avec le processus ci-dessous. Celui-ci utilise l'appel système `getpid(2)`_ pour récupérer son :term:`pid`, l'affiche et utilise la fonction `sleep(3)`_ de la librairie pour se mettre en veille pendant trente secondes avant de se terminer. -.. literalinclude:: /Outils/src/getpid.c +.. literalinclude:: src/getpid.c :encoding: utf-8 :language: c :start-after: ///AAA @@ -37,7 +37,7 @@ Ce programme peut être compilé avec `gcc(1)`_ pour produire un exécutable. -rwxr-xr-x 1 obo obo 8800 10 fév 12:12 getpid -rw-r--r-- 1 obo obo 608 10 fév 12:11 getpid.c -Cet exemple utilise la commande `ls(1)`_ pour lister le contenu d'un répertoire. L'argument ``-l`` permet de d'obtenir pour chaque fichier son nom, sa date de modification, sa taille, l'utilisateur et le group auxquels il appartient ainsi que ses permissions. Sous Unix, les permissions associées à un fichier sont divisées en trois blocs. Le premier bloc correspond aux permissions qui sont applicables à l'utilisateur qui possède le fichier. Pour l'exécutable ``getpid``, les permissions du propriétaire sont ``rwx``. Elles indiquent que le propriétaire peut lire le fichier (permission ``r``), l'écrire ou l'effacer (permission ``w``) et l'exécuter (permission ``x``). Sous Unix, seuls les fichiers qui possèdent la permission à l'exécution peuvent être lancés depuis l'interpréteur. Ces permissions peuvent être modifiées en utilisant la commande `chmod(1)`_. Les deux autres blocs de permissions sont relatifs aux membres du même groupe que le propriétaire et à un utilisateur quelconque. Nous y reviendrons plus en détails lorsque nous aborderons les systèmes de fichiers. En pratique, il est important de savoir qu'un fichier shell ou un fichier compilé qui n'a pas le bit de permission ``x`` ne peut pas être exécuté par le système. Ceci est illustré par l'exemple ci-dessous. +Cet exemple utilise la commande `ls(1)`_ pour lister le contenu d'un répertoire. L'argument ``-l`` permet de d'obtenir pour chaque fichier son nom, sa date de modification, sa taille, l'utilisateur et le groupe auquel il appartient ainsi que ses permissions. Sous Unix, les permissions associées à un fichier sont divisées en trois blocs. Le premier bloc correspond aux permissions qui sont applicables à l'utilisateur qui possède le fichier. Pour l'exécutable ``getpid``, les permissions du propriétaire sont ``rwx``. Elles indiquent que le propriétaire peut lire le fichier (permission ``r``), l'écrire ou l'effacer (permission ``w``) et l'exécuter (permission ``x``). Sous Unix, seuls les fichiers qui possèdent la permission à l'exécution peuvent être lancés depuis l'interpréteur. Ces permissions peuvent être modifiées en utilisant la commande `chmod(1)`_. Les deux autres blocs de permissions sont relatifs aux membres du même groupe que le propriétaire et à un utilisateur quelconque. Nous y reviendrons plus en détail lorsque nous abordons les systèmes de fichiers. En pratique, il est important de savoir qu'un fichier shell ou un fichier compilé qui n'a pas le bit de permission ``x`` ne peut pas être exécuté par le système. Ceci est illustré par l'exemple ci-dessous. .. code-block:: console @@ -59,7 +59,7 @@ L'interpréteur de commande `bash(1)`_ permet lancer plusieurs processus en tâc [1] 10975 $ Processus : 10975 [pid=10975] Sleep : 30 secondes - ./getpid & + $ ./getpid & [2] 10976 $ Processus : 10976 [pid=10976] Sleep : 30 secondes @@ -68,7 +68,7 @@ L'interpréteur de commande `bash(1)`_ permet lancer plusieurs processus en tâc obo 8361 0,0 0,0 2435548 208 s003 S+ 9:24 0:00.14 -bash obo 10975 0,0 0,0 2434832 340 s000 S 12:05 0:00.00 ./getpid obo 10976 0,0 0,0 2434832 340 s000 S 12:05 0:00.00 ./getpid - $ [pid=10975] Fin du processus + [pid=10975] Fin du processus [pid=10976] Fin du processus [1]- Done ./getpid [2]+ Done ./getpid @@ -85,7 +85,7 @@ Si le programme a été lancé depuis un shell, il suffit généralement de tape ^C -Parfois cependant `Ctrl-C` n'est pas suffisant. C'est le cas notamment lorsqu'un processus a été lancé en tâche de fond. Dans ce cas, la meilleure technique est d'utiliser `ps(1)`_ pour trouver l'identifiant du processus et l'interrompre via la commande `kill(1)`_. Cette commande permet d'envoyer un :term:`signal` au processus. Nous verrons plus tard le fonctionnement des signaux sous Unix. A ce stade, le signal permettant de terminer avec certitude un processus est le signal ``KILL``. C'est celui qui est utilisé dans l'exemple ci-dessous. +Parfois cependant `Ctrl-C` n'est pas suffisant. C'est le cas notamment lorsqu'un processus a été lancé en tâche de fond. Dans ce cas, la meilleure technique est d'utiliser `ps(1)`_ pour trouver l'identifiant du processus et l'interrompre via la commande `kill(1)`_. Cette commande permet d'envoyer un :term:`signal` au processus. Nous verrons plus tard le fonctionnement des signaux sous Unix. À ce stade, le signal permettant de terminer avec certitude un processus est le signal ``KILL``. C'est celui qui est utilisé dans l'exemple ci-dessous. .. code-block:: console diff --git a/Outils/shell.rst b/Outils/shell.rst index 5e2b72d419890f0149f0c49a1238a8a94ceee453..b294e803332b3d27cf5c6bc964a14c77188ba1c0 100644 --- a/Outils/shell.rst +++ b/Outils/shell.rst @@ -6,11 +6,11 @@ Shell ===== -L'interprèteur de commande, ou shell, est l'interface de communication entre l'utilisateur et le système d'exploitation. C'est un exécutable chargé d'interpréter les commandes écrites par l'utilisateur et de les exécuter. +L'interpréteur de commande, ou shell, est l'interface de communication entre l'utilisateur et le système d'exploitation. C'est un exécutable chargé d'interpréter les commandes écrites par l'utilisateur et de les exécuter. -Dans le cadre de ce cours nous utiliserons l'interpreteur `bash(1)`_. Cet exécutable est généralement placé dans le fichier ``/bin/bash``. +Dans le cadre de ce cours nous utiliserons l'interpréteur `bash(1)`_. Cet exécutable est généralement placé dans le fichier ``/bin/bash``. -Le shell est un outil très puissant. Il permet d'effectuer de nombreuses opérations qui peuvent difficilement être réalisées manuellement ou via une interface graphiques. +Le shell est un outil très puissant. Il permet d'effectuer de nombreuses opérations qui peuvent difficilement être réalisées manuellement ou via une interface graphique. .. note:: Astuce : utilisez la complétion @@ -29,7 +29,7 @@ Le shell est un outil très puissant. Il permet d'effectuer de nombreuses opéra Expressions régulières ---------------------- -Avant de commencer à voir les commandes utiles avec le shell, il est important de définir ce qu'est une expression régulière (`regex(3)`). Les expresions régulières caractérisent des chaînes de caractères et elles sont utiles pour de nombreuses commandes. Nous l'utiliserons notamment pour faire une recherche dans un fichier. +Avant de commencer à voir les commandes utiles avec le shell, il est important de définir ce qu'est une expression régulière (`regex(3)`). Les expressions régulières caractérisent des chaînes de caractères et elles sont utiles pour de nombreuses commandes. Nous l'utiliserons notamment pour faire une recherche dans un fichier. Dans une regex, certains caractères ont une signification particulière : @@ -58,7 +58,7 @@ Notes : - ``^b$`` = contient uniquement le caractère ``b`` - ``^$`` = la ligne est vide -Nous verrons plus en détails leur utilisation avec les commandes plus complexes. +Nous verrons plus en détail leur utilisation avec les commandes plus complexes. Manipulation des répertoires @@ -73,7 +73,7 @@ Il est possible de changer le répertoire courant du processus ou du shell en ut - `cd(1posix)`_ .. : remonte dans le répertoire prédécesseur dans l'arborescence des fichiers. La commande `mkdir(1)`_ permet de créer un répertoire. Elle prend comme argument le nom du répertoire à créer. -La commande `rmdir(1)`_ supprime un répertoire qui doit être vide vide. Pour effacer un répertoire et tous les fichiers qu'il contient, il faut utiliser la commande `rm(1)`_ avec l'option ``-r``. Ainsi, ``rm -r /tmp/t`` supprime le répertoire ``/tmp/t`` ainsi que tous les fichiers et sous-répertoire se trouvant dans ce répertoire. +La commande `rmdir(1)`_ supprime un répertoire qui doit être vide. Pour effacer un répertoire et tous les fichiers qu'il contient, il faut utiliser la commande `rm(1)`_ avec l'option ``-r``. Ainsi, ``rm -r /tmp/t`` supprime le répertoire ``/tmp/t`` ainsi que tous les fichiers et sous-répertoires se trouvant dans ce répertoire. La commande `ls(1)`_ permet de connaître l'ensemble des fichiers et répertoires contenus dans le répertoire courant. Elle supporte plusieurs options dont les plus utiles sont : @@ -82,7 +82,7 @@ La commande `ls(1)`_ permet de connaître l'ensemble des fichiers et répertoire * ``-d`` : Evite de lister le contenu d'un répertoire : si `rep` est un répertoire, ``ls -l`` `rep` listera le contenu du répertoire `rep`, alors que ``ls -ld`` `rep` listera la description du répertoire * ``-l`` : Description complète du contenu d'un répertoire (une ligne par fichier) -Avec l'option ``-l``, le premier caractère de la ligne indique le type du fichier. Le caractère ``-`` correspond à un fichier standard et ``d`` à un répertoire. Il est aussi possible de connaître le contenu d'un autre répertoire quel le répertoire courant en fournissant le nom de ce répertoire comme argument à la commande ``ls``. +Avec l'option ``-l``, le premier caractère de la ligne indique le type du fichier. Le caractère ``-`` correspond à un fichier standard et ``d`` à un répertoire. Il est aussi possible de connaître le contenu d'un autre répertoire que le répertoire courant en fournissant le nom de ce répertoire comme argument à la commande ``ls``. .. code-block:: console @@ -99,32 +99,32 @@ Manipulation de fichiers Créer et détruire ^^^^^^^^^^^^^^^^^ -> filename Crée un fichier vide. -`touch(1)`_ filename Crée un fichier vide. -`echo(1)`_ mon_texte > filename Crée un fichier avec "mon_texte" dedans. - -`rm(1)`_ [-irf] files efface les fichiers + * > filename crée un fichier vide. + * `touch(1)`_ filename crée un fichier vide. + * `echo(1)`_ mon_texte > filename crée un fichier avec "mon_texte" dedans. + + `rm(1)`_ [-irf] files efface les fichiers * -i : intéractif, demande une confirmation sur chaque fichier * -f : force la suppression du fichier - * -r : Efface un répertoire et son contenu + * -r : efface un répertoire et son contenu Visualiser ^^^^^^^^^^ -`cat(1)`_ [-opt] f1 f2 concatène et affiche les deux fichiers. -`cat(1)`_ [-opt] file Affiche le fichier sur la sortie standard. + * `cat(1)`_ [-opt] f1 f2 concatène et affiche les deux fichiers. + * `cat(1)`_ [-opt] file affiche le fichier sur la sortie standard. * -v : convertit les caractères spéciaux en caractères affichables * -n : numérote les lignes * -b : numérote seulement les lignes non vides * -E : affiche le symbôle $ à la fin de chaque ligne - * -T : affiche les caractères de tabulations comme ^I + * -T : affiche les caractères de tabulation comme ^I * -A : équivalent à -vET * -e : équivalent à -vE * -t : équivalent à -vT Avec cat, il est possible d'écrire depuis la console dans un fichier. - Appuyer sur ctrl+D au début d'une ligne pour terminer la saisie + Appuyez sur ctrl+D au début d'une ligne pour terminer la saisie .. code-block:: console @@ -143,12 +143,12 @@ Visualiser et je rajoute ceci à la fin -`nl(1)`_ [-opt] file Affiche le contenu d'un fichier et en numérote les lignes. - * -bt : numérote les lignes non-vides (par défaut) +`nl(1)`_ [-opt] file affiche le contenu d'un fichier et en numérote les lignes. + * -bt : numérote les lignes non vides (par défaut) * -ba : numérote toutes les lignes * -bpXXX : numérote seulement les lignes qui contiennent la chaîne de caractères XXX - * -sX : supprime le décalage du à la numérotation et utilise le séparateur X - * -s'XXX' : supprime le décalage du à la numérotation et utilise la chaîne 'XXX' + * -sX   : supprime le décalage dû à la numérotation et utilise le séparateur X + * -s'XXX' : supprime le décalage dû à la numérotation et utilise la chaîne 'XXX' `paste(1)`_ [-opt] f1 f2 concatène horizontalement et affiche les deux fichiers. * -s : copie les lignes d'un fichier sur une ligne @@ -156,21 +156,21 @@ Visualiser `more(1)`_ file visualise le contenu du ou des fichiers par page. Si il contient plus d'une page : * q ou Q : pour terminer la visualisation - * RETURN : pour visualiser une ligne supplémentaire - * ESPACE : pour visualiser la page suivante - * h : pour obtenir de l'aide + * RETURN : pour visualiser une ligne supplémentaire + * ESPACE : pour visualiser la page suivante + * h : pour obtenir de l'aide Modifier ^^^^^^^^ -`touch(1)`_ filename Met à jour les dates d'accès et de modification du fichier. Crée le fichier si il n'existe pas. - * -c : empeche la création du fichier si celui ci n'existe pas +`touch(1)`_ filename met à jour les dates d'accès et de modification du fichier. Crée le fichier si il n'existe pas. + * -c : empêche la création du fichier si celui ci n'existe pas * -m : change uniquement la date de modification du fichier - * -a : change uniquement la date d'acces du fichier + * -a : change uniquement la date d'accès du fichier -`split(1)`_ [-opt] file [out] Coupe le fichier en plusieurs petite partie - * -b nbr : decoupe selon un nombre d'octet - * -n nbr : decoupe selon un de ligne +`split(1)`_ [-opt] file [out] coupe le fichier en plusieurs petites parties + * -b nbr : decoupe selon un nombre d'octets + * -n nbr : decoupe selon un nombre de lignes Extraction de données ^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ Extraction de données * -o : modifie la sortie standard * -t : modifie le caractère séparateur. Par défaut c'est une chaîne de blancs * -n : compare selon la valeur arithmétique - * -k : spécifie la colonne utilisé pour le tri + * -k : spécifie la colonne utilisée pour le tri uniq et sort sont souvent utilisés ensemble. Par exemple, cette commande trie les lignes de file.txt selon leur nombre d'apparitions. @@ -233,7 +233,7 @@ Extraction de données zorro,01,20 zorro,5,4 - $ cat file.txt | sort -t; -k2n + $ cat file.txt | sort -t, -k2n zorro,01,20 pcr,01,3 pcr,1,3 @@ -246,8 +246,8 @@ Extraction de données * -i : ignore la casse * -c : rapport plus clair * -q : indique uniquement si les fichiers sont différents - * -b : ignore les différences du à des espaces blancs - * -B : ignore les différences du à des lignes blanches + * -b : ignore les différences dues à des espaces blancs + * -B : ignore les différences dues à des lignes blanches .. code-block:: console @@ -282,22 +282,22 @@ Extraction de données Obtenir des informations ^^^^^^^^^^^^^^^^^^^^^^^^ -`wc(1)`_ [-opt] filename Donne sur stdout des informations au sujet de l'entrée standard ou d'une liste de fichiers. +`wc(1)`_ [-opt] filename donne sur stdout des informations au sujet de l'entrée standard ou d'une liste de fichiers. Première colonne est le nombre de lignes, deuxième le nombre de mots et en dernier le nombre d'octets. * -l : nombre de lignes * -c : nombre d'octets * -m : nombre de caractères - * -L : la longueur de la plus longue d'une ligne + * -L : la longueur de la plus longue ligne * -w : le nombre de mots -Manipulation communes aux répertoires et fichiers -------------------------------------------------- +Manipulations communes aux répertoires et fichiers +-------------------------------------------------- Copier ^^^^^^ `cp(1)`_ [-opt] src dst copie la src dans le fichier dst. - Si dst n'existe pas, il est créé. Sinon, si c'est un fichier, son contenu est ecrasé. + Si dst n'existe pas, il est créé. Sinon, si c'est un fichier, son contenu est écrasé. * -r : spécifie la copie d'un répertoire * -u : copie uniquement si src est plus récent que dst ou si il est manquant dans dst @@ -312,10 +312,10 @@ Copier Déplacer ou renomer ^^^^^^^^^^^^^^^^^^^ -`mv(1)`_ [-opt] src dst renomme ou deplace src en dst. - * -f : ecrase les fichiers existant - * -i : demande comfirmation avant d'écraser un fichier existant - * -n : n'ecrase aucun fichier déja existant +`mv(1)`_ [-opt] src dst renomme ou déplace src en dst. + * -f : écrase les fichiers existants + * -i : demande confirmation avant d'écraser un fichier existant + * -n : n'écrase aucun fichier déja existant Note : Si la destination est un répertoire, alors la source peut être une liste de fichiers. @@ -333,7 +333,7 @@ Pour les critères de recherche : * !critère = non logique * critère1 -a critère2 = ou logique -`find(1)`_ chemin regex recherche les fichiers/répertoire caractérisé par nom, à partir du répertoire rep et affiche le résultat. +`find(1)`_ chemin regex recherche les fichiers/répertoires caractérisés par nom, à partir du répertoire rep et affiche le résultat. * -name : sur le nom du fichier * -perm : sur les droits d'accès du fichier * -links : sur le nombre de liens du fichier @@ -359,12 +359,12 @@ Pour les critères de recherche : * Il est parfois nécessaire de mettre -print dans la commande pour afficher le résultat - * Lors de larges recherches, il peut y avoir un message d'erreur pour chaque tentative d'accès à un fichier où vous n'avez pas d'autorisation d'accès, par exemple des fichiers systemes. Pour éviter que ces messages d'erreurs ne polluent la recherche, il faut rediriger la sortie d'erreur standard dans "un puit sans fond". Pour cela, rajouter 2>/dev/null + * Lors de larges recherches, il peut y avoir un message d'erreur pour chaque tentative d'accès à un fichier où vous n'avez pas d'autorisation d'accès, par exemple des fichiers système. Pour éviter que ces messages d'erreur ne polluent la recherche, il faut rediriger la sortie d'erreur standard dans "un puits sans fond". Pour cela, rajoutez 2>/dev/null - * Il est parfois très utile de pouvoir exécuter une commande sur les fichiers trouvés. La solution la plus légère est de rediriger la sortie et de lui attribuer une commande. Pour cela, il faut faire : "find rep -name expr| xargs commande". Cette commande est expliqué dans la section "Commandes plus complexes". + * Il est parfois très utile de pouvoir exécuter une commande sur les fichiers trouvés. La solution la plus légère est de rediriger la sortie et de lui attribuer une commande. Pour cela, il faut faire : "find rep -name expr| xargs commande". Cette commande est expliquée dans la section "Commandes plus complexes". - Pour cet exemple, le résultat est tout les fichiers dont le nom contient "mon test", et donc le fichier contient "supertab". + Pour cet exemple, le résultat est tous les fichiers dont le nom contient "mon test", et donc le fichier contient "supertab". .. code-block:: console $ find /testdirectory -name *mon test* -type f | xargs grep supertab @@ -373,10 +373,10 @@ Pour les critères de recherche : Création de lien ^^^^^^^^^^^^^^^^ -`ln(1)`_ [-opt] src dst Création d'un lien (raccourci) sur un fichier ou un répertoire. Attention un lien n'est pas une copie. +`ln(1)`_ [-opt] src dst création d'un lien (raccourci) sur un fichier ou un répertoire. Attention un lien n'est pas une copie. Il existe deux sortes de liens: * le lien physique : uniquement des fichiers - * le lien symbolique (avec l'option -s) : fichier et répertoires + * le lien symbolique (avec l'option -s) : fichiers et répertoires "SHEMA" @@ -388,7 +388,7 @@ Archivage et compression Il est important de noter qu'une archive n'est pas forcément compressée. -`tar(1)`_ [-opt] tarname.tar files crée une archive à partir d'une liste de fichier ou de répertoires. +`tar(1)`_ [-opt] tarname.tar files crée une archive à partir d'une liste de fichiers ou de répertoires. * f : argument obligatoire, sauf si l'on veut lire ou écrire vers/depuis un lecteur de bande * c : crée une archive * z : compresse l'archive créée, en utilisant gzip. (Attention, l'extension doit être "tar.gz") @@ -396,7 +396,7 @@ Il est important de noter qu'une archive n'est pas forcément compressée. * x : désarchive * t : inspection de l'archive - .. code-block:: console + .. code-block:: none $ tar cf monarchive.tar firstfile.c secondfile.c = crée une archive contenant deux fichiers $ tar cfz monarchive.tar.gz firstfile.c secondfile.c = crée une archive compressée @@ -408,7 +408,7 @@ Il est important de noter qu'une archive n'est pas forcément compressée. `gzip(1)`_ file compresse un fichier ou une archive - * -c : la compression est effectuée sur la sortie standard au lieu du fichier lui même + * -c : la compression est effectuée sur la sortie standard au lieu du fichier lui-même * -c1 : compression plus rapide * -c9 : meilleur compression @@ -446,7 +446,7 @@ Les permissions accordées à ces trois classes sont : 111 101 100 (en binaire) 7 5 4 (en hexadecimal) - d'ou la commande ``chmod 754 fichier`` + d'où la commande ``chmod 754 fichier`` `chown(1)`_ owner files change le propriétaire du fichier. @@ -456,11 +456,11 @@ Les permissions accordées à ces trois classes sont : Obtenir des informations ^^^^^^^^^^^^^^^^^^^^^^^^ -`stat(1)`_ [-opt] filename donne des informations sur les métadonnées associéées au fichier - * -f : affiche l'état du systeme de fichiers plutot que celui du fichier +`stat(1)`_ [-opt] filename donne des informations sur les métadonnées associées au fichier + * -f : affiche l'état du système de fichiers plutôt que celui du fichier * -L : suit les liens du fichier * -t : affiche les informations de façon concise - * --format=FORMAT : affiche les information selon le format choisi + * --format=FORMAT : affiche les informations selon le format choisi .. code-block:: console @@ -489,7 +489,7 @@ Obtenir des informations %y date de la dernière modification au format lisible %z date du dernier changement au format lisible - Séquences de format valables pour les systemes de fichiers : + Séquences de format valables pour les systèmes de fichiers : %a nombre de blocs libres disponibles pour les utilisateurs normaux %b nombre total de blocs de données dans le système de fichiers %c nombre total d'inodes dans le système de fichiers @@ -525,11 +525,11 @@ Gestion des processus `lsof(8)`_ [-opt] affiche les fichiers ouverts. * -p PID : uniquement les fichiers ouverts du processus - * -i : affiche les connexions réseaux ouvertes + * -i : affiche les connexions réseau ouvertes .. code-block:: console - $ lsof -i -p 2735 = Les connexions ouvertes ET les fichiers ouvert par le processus 2735 + $ lsof -i -p 2735 = Les connexions ouvertes ET les fichiers ouverts par le processus 2735 $ lsof -i -a -p 2735 = Les connexions ouvertes par le processus 2735 @@ -544,28 +544,27 @@ Redirection de l'entrée, sortie et erreur standard Lors de l'exécution d'une commande, un processus est créé et celui-ci va ouvrir trois flux : l'entrée, la sortie et l'erreur standard. Par défaut lorsque l'on exécute un programme, les données sont donc lues à partir du clavier et le programme envoie sa sortie et ses erreurs sur l'écran. toutefois, il est possible de rediriger ces flux. - < l'entrée standard est lue à partir d'un fichier - > La sortie standard est redirigée dans un fichier. Si le fichier existe, il est vidé avant d'écrire. - >> La sortie standard est redirigée dans un fichier. Si le fichier existe, la sortie standart est ajouté à la fin de celui ci. - 2> La sortie d'erreur standard est redirigée - - cmd1 | cmd2 La sortie standard de cmd1 devient l'entrée standard de cmd2 + * < l'entrée standard est lue à partir d'un fichier + * > La sortie standard est redirigée dans un fichier. Si le fichier existe, il est vidé avant d'écrire. + * >> La sortie standard est redirigée dans un fichier. Si le fichier existe, la sortie standard est ajoutée à la fin de celui ci. + * 2> La sortie d'erreur standard est redirigée + * cmd1 | cmd2 La sortie standard de cmd1 devient l'entrée standard de cmd2 Symboles pour les commandes ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``?`` caractère joker remplaçant un seul caractère - ``!`` Inverse le sens d’un test ou l’état de sortie d’une commande. + * ``?`` caractère joker remplaçant un seul caractère + * ``!`` inverse le sens d’un test ou l’état de sortie d’une commande. - ``*`` caractère joker remplaçant une chaîne de caractère - ``&`` exécute une commande en arrière plan - ``;`` sépare des instructions sur une seule ligne + * ``*`` caractère joker remplaçant une chaîne de caractères + * ``&`` exécute une commande en arrière-plan + * ``;`` sépare des instructions sur une seule ligne - ``cmd1 && cmd 2`` cmd2 n'est exécuté que si cmd1 réussi - ``cmd1 || cmd 2`` cmd2 n'est exécuté que si cmd1 échoue + * ``cmd1 && cmd 2`` cmd2 n'est exécuté que si cmd1 réussit + * ``cmd1 || cmd 2`` cmd2 n'est exécuté que si cmd1 échoue - ``\`` annule l'effet du caractère spécial suivant - ``" "`` annule l'effet de tout les caractères spéciaux entre les guillemets, sauf ``$`` et ``\`` + * ``\`` annule l'effet du caractère spécial suivant + * ``" "`` annule l'effet de tous les caractères spéciaux entre les guillemets, sauf ``$`` et ``\`` Commandes utiles @@ -574,15 +573,15 @@ Commandes utiles Pour effectuer des chaînes ^^^^^^^^^^^^^^^^^^^^^^^^^^ -`xargs(1)`_ Il permet d'appliquer une commande à l'entrée standard. +`xargs(1)`_ permet d'appliquer une commande à l'entrée standard. - Pour cet exemple, le résultat est tous les fichiers dont le nom contient "mon test", et donc le fichier contient "supertab". + Pour cet exemple, le résultat est tous les fichiers dont le nom contient "mon test", et dont le fichier contient "supertab". .. code-block:: console $ find /testdirectory -name *mon test* -type f | xargs grep supertab -`tee(1)`_ file lit depuis l'entrée standard, écrit dans la sortie standard et dans le fichier. Elle est utilisé pour continuer une chaîne tout en faisant une sauvegarde des informations +`tee(1)`_ file lit depuis l'entrée standard, écrit dans la sortie standard et dans le fichier. Elle est utilisée pour continuer une chaîne tout en faisant une sauvegarde des informations. .. code-block:: console @@ -591,32 +590,36 @@ Pour effectuer des chaînes % cat fichier.txt Les tubes sont un mécanisme puissant. - On peut voir que le texte a bien été relayé vers la commande "wc" et qu'en même temps, ce texte à été écrit dans fichier.txt + On peut voir que le texte a bien été relayé vers la commande "wc" et qu'en même temps, ce texte a été écrit dans fichier.txt Informations générales ^^^^^^^^^^^^^^^^^^^^^^ -`su(1)`_ Passe en mode "root", c'est à dire administrateur +`su(1)`_ passe en mode "root", c'est à dire administrateur + +`whatis(1)`_ cmd explique briévement l'utilité d'une commande -`whatis(1)`_ cmd Explique briévement l'utilité d'une commande -`apropos(1)`_ [-opt] motclé Recherche dans les man pages les commandes correspondants aux mots clés. +`apropos(1)`_ [-opt] motclé recherche dans les man pages les commandes correspondants aux mots clés. * -a : Affiche seulement les résultats répondant à tout les mots clés. L'inverse est le fonctionnement par défault -`date(1)`_ Donne l'heure, selon l'horloge de votre ordinateur -`cal(1)`_ Affiche un calendrier du mois courant +`date(1)`_ donne l'heure, selon l'horloge de votre ordinateur + +`cal(1)`_ affiche un calendrier du mois courant -`halt(8)`_ Eteint l'ordinateur. -`reboot(8)`_ Redémarre l'ordinateur +`halt(8)`_ éteint l'ordinateur. + +`reboot(8)`_ redémarre l'ordinateur Informations système ^^^^^^^^^^^^^^^^^^^^ -`time(1posix)`_ programme Permet de calculer le temps d'exécution d'un programme +`time(1posix)`_ programme permet de calculer le temps d'exécution d'un programme -`df(1)`_ [-opt] [file] Indique l'espace disque utilisé et disponible sur tous les systèmes de fichiers. - Si des fichiers sont passés en arguments, seul les systemes de fichier contenant un des fichiers sont montrés. +`df(1)`_ [-opt] [file] indique l'espace disque utilisé et disponible sur tous les systèmes de fichiers. + Si des fichiers sont passés en argument, seul les systèmes de fichiers contenant un des fichiers sont montrés. + * -h Imprime les dimensions dans un format lisible par l’utilisateur * -H Idem que -h, mais il utilise des puissances de 1000 au lieu de 1024 * -i Affiche l’information i-node au lieu de l’utilisation des blocs @@ -630,16 +633,16 @@ Maniement des jobs La plupart des commandes en console sont exécutées rapidement, mais ce n'est pas le cas de toutes. Certaines commandes, que l'on va appeler `jobs`, prennent plus de temps (comme par exemple copier un très gros fichier), et d'autres encore tournent indéfiniment. -Evidemment, quand un job est en cours d'exécution à la console, plus aucune action ne peut être faite sur celle-ci. Unix nous vient en aide dans ce cas là avec les le raccourci ``Ctrl+z`` et les commandes `jobs(1)`_, `bg(1)`_ et `fg(1)`_. +Évidemment, quand un job est en cours d'exécution à la console, plus aucune action ne peut être faite sur celle-ci. Unix nous vient en aide dans ce cas-là avec le raccourci ``Ctrl+z`` et les commandes `jobs(1)`_, `bg(1)`_ et `fg(1)`_. * ``Ctrl+z`` : Le job passe dans l'état ``suspended``. Il est en pause, et placé en background. * ``jobs`` : Affiche à la console la liste des jobs présents en background * ``bg`` : Passe un job mis en background de l'état ``suspended`` à l'état ``running``. Le job reste en background, mais il continue à s'exécuter - * ``fg`` : Passe un job du background à l'avant plan + * ``fg`` : Passe un job du background à l'avant-plan Exemples : - .. code-block:: console + .. code-block:: none $ yes > \dev\null #nous lançons la commande yes @@ -647,7 +650,7 @@ Exemples : ^Z #nous la suspendons avec Ctrl+z [1]+ Stopped yes > \dev\null - #elle est placé en arrière plan + #elle est placée en arrière-plan $ jobs #nous regardons la liste des jobs en arrière plan @@ -655,9 +658,9 @@ Exemples : #chaque job à un numéro qui lui est attribué. ici 1 $ bg 1 - #nous relançons yes en arrière plan. on peut utiliser son nom comme son numéro avec la commande bg et fg + #nous relançons yes en arrière-plan. On peut utiliser son nom comme son numéro avec la commande bg et fg [1]+ yes > \dev\null & - #yes set remix en route + #yes s'est remis en route $ jobs #nous vérifions le statut de yes avec jobs @@ -665,7 +668,7 @@ Exemples : #il est en cours d'exécution $ fg yes - #nous remettons yes en avant plan + #nous remettons yes en avant-plan yes > \dev\null ^Z @@ -679,7 +682,7 @@ Exemples : $ jobs #nous vérifions les jobs [1]+ Terminated: 15 yes > \dev\null - #yes set marqué Terminated + #yes est marqué Terminated $ jobs #un deuxième appel à jobs nous affiche une liste vide @@ -698,99 +701,107 @@ Modification d'un fichier -`sed(1)`_ [-n] [-e 'prog'] [-f cmdfile] [file] Applique des commandes de 'prog' sur un fichier +`sed(1)`_ [-n] [-e 'prog'] [-f cmdfile] [file] applique des commandes de 'prog' sur un fichier - * -n : n'affiche aucune ligne, sauf celle spécifié avec la commande p + * -n : n'affiche aucune ligne, sauf celle spécifiée avec la commande p * -e : specifie les commandes à appliquer sur le fichier - Note : I faut mieux encadrer la commande avec des ' ou des " - * -f : les commandes sont lu à partir d'un fichier + Note : Il vaut mieux encadrer la commande avec des ' ou des " + * -f : les commandes sont lues à partir d'un fichier Pour bien comprendre la puissance de sed, il est important de comprendre son fonctionnement. sed fonctionne en 4 étapes : * Lecture d'une ligne sur le flux d'entrée, et stockage dans l'espace de travail - * Execute les commandes sur l'espace de travail + * Exécute les commandes sur l'espace de travail * Envoie la ligne au flux de sortie en lui rajoutant un '\n' * Recommence avec la ligne suivante ... -Une commande d'un 'prog' est constitué d'un adressage, c-à -d les lignes sur lequelle la commande est appliquée, et de l'action à exécuter. +Une commande d'un 'prog' est constituée d'un adressage, c-à -d les lignes sur lesquelles la commande est appliquée, et de l'action à exécuter. 1) L'adressage est décomposé en deux catégories. * : toutes les lignes - * num : la ligne "num". La dernière ligne est symbolisé par $ + * num : la ligne "num". La dernière ligne est symbolisée par $ * num1, num2 : les lignes entre num1 et num2 - * /regex/ : les lignes correspondants à l'expression régulière regex + * /regex/ : les lignes correspondant à l'expression régulière regex * /regex1/, /regex2/ : les lignes entre la première ligne correspondant à regex1 et la première ligne correspondant à regex2 - Si regex2 est vide, la commande sera appliqué jusqu'à la fin du fichier. + Si regex2 est vide, la commande sera appliquée jusqu'à la fin du fichier. Note : Le ! représente la négation. Mettez le après votre spécification des lignes pour prendre la négation RAPPEL sur les regex : - \ Caractère d'échappement [\.] contient un "." - ^ Début de ligne ^b commence par b - . N'importe quel caractère ^.$ contient un seul caractère - $ Fin de ligne er$ finit par "er" - | Alternative ^(a|A) commence par a ou A - ( ) Groupement ^((a)|(er)) commence par a ou er - - Intervalle de caractères ^[a-d] commence par a,b,c ou d - [ ] Ensemble de caractères [0-9] contient un chiffre - [^] Tout sauf un ensemble de caractères ^[^a] ne commence pas par a - + 1 fois ou plus ^(a)+ commence par un ou plusieurs a - ? 0 ou 1 fois ^(a)? commence ou non par un a - * 0 fois ou plus ^(a)* peut ou non commencer par a - {x} x fois exactement a{2} deux fois "a" - {x,} x fois au moins a{2,} deux fois "a" au moins - {x, y} x fois minimum, y maximum a{2,4} deux, trois ou quatre fois "a" + + ============= ==================================== ==================================================== + Expression Explication Exemple + ============= ==================================== ==================================================== + ``\`` Caractère d'échappement ``[\.]`` contient un "." + ``^`` Début de ligne ``^b`` commence par b + ``.`` N'importe quel caractère ``^.$`` contient un seul caractère + ``$`` Fin de ligne ``er$`` finit par "er" + ``|`` Alternative ``^(a|A)`` commence par a ou A + ``( )`` Groupement ``^((a)|(er))`` commence par a ou er + ``-`` Intervalle de caractères ``^[a-d]`` commence par a,b,c ou d + ``[ ]`` Ensemble de caractères ``[0-9]`` contient un chiffre + ``[^]`` Tout sauf un ensemble de caractères ``^[^a]`` ne commence pas par a + ``+`` 1 fois ou plus ``^(a)+`` commence par un ou plusieurs a + ``?`` 0 ou 1 fois ``^(a)?`` commence ou non par un a + ``*`` 0 fois ou plus ``^(a)*`` peut ou non commencer par a + ``{x}`` x fois exactement ``a{2}`` deux fois "a" + ``{x,}`` x fois au moins ``a{2,}`` deux fois "a" au moins + ``{x, y}`` x fois minimum, y maximum ``a{2,4}`` deux, trois ou quatre fois "a" + ============= ==================================== ==================================================== - Note : - ^b$ = contient uniquement b - ^$ = la ligne est vide + Notes : + + - ``^b$`` = contient uniquement le caractère ``b`` + - ``^$`` = la ligne est vide 2) Les actions * p : affiche les lignes * d : supprime les lignes - * y/l1/l2 : remplace les caractères de la première liste par les caractère de la seconde + * y/l1/l2 : remplace les caractères de la première liste par les caractères de la seconde * s/mtf/sbst/ : substitue le mtf par le sbst - Note : Par défaut seule la première occurence est remplacé. - Pour toutes les remplacées : /s/motif/substitut/g - Pour en remplacer 4 : /s/motif/substitut/4 + Note : Par défaut seule la première occurrence est remplacée. + * Pour toutes les remplacer : /s/motif/substitut/g + * Pour en remplacer 4 : /s/motif/substitut/4 * N : charge une ligne supplémentaire dans l'espace de travail - * D : Efface l'espace de travail jusqu'au premier saut de ligne incorporé - * b : Reviens + * D : efface l'espace de travail jusqu'au premier saut de ligne incorporé + * b : revient - Pour faire des commandes groupées, placer vos commandes entre {} spérarées par ;. + Pour faire des commandes groupées, placez vos commandes entre {} séparées par ";". - Quel illustrations basiques : + Quelques illustrations basiques : - .. code-block:: console + .. code-block:: none - $ sed '' test.txt = Le script est vide, il renvoit simplement le fichier + $ sed '' test.txt = Le script est vide, il renvoie simplement le fichier $ sed -n '/Ici/p' test.txt = Affiche les lignes contenant Ici - $ sed 'p' test.txt = Double toute les lignes + $ sed 'p' test.txt = Double toutes les lignes - $ sed -e '4d; 7d' test.txt = Supprime les ligne 4 et 7 + $ sed -e '4d; 7d' test.txt = Supprime les lignes 4 et 7 $ sed -e '4,7d' test.txt = Supprime les lignes entre 4 et 7 $ sed '/^#/ d' test.txt = Supprime les lignes commencant par # $ sed '/e$/ d' test.txt = Supprime les lignes se terminant par e - $ sed '/#/,/@/d' test.txt = supprime les lignes comprises entre le premier # et le premier @ + $ sed '/#/,/@/d' test.txt = Supprime les lignes comprises entre le premier # et le premier @ - $ sed -e 's/^#//' test.txt = Supprime le commentaire en début de ligne, puisqu'il est remplacé par '' + $ sed -e 's/^#//' test.txt = Supprime le commentaire en début de ligne, puisqu'il + est remplacé par '' - $ sed -e 'y/éèê/eee/' test.txt = Retire les accents, puisqu'ils sont remplacé par 'e' + $ sed -e 'y/éèê/eee/' test.txt = Retire les accents, puisqu'ils sont remplacés par 'e' $ sed -e ' 4,7 {y/éèê/eee/;s/e/[]/} test.txt = Remplace les accents, puis remplace les "e" par "[]" - $ sed -e '/^$/ {N; D}' test.txt = Suprimme les sauts à la lignes - | - --> Explication : Pour les lignes vides, on charge la ligne suivant, on envoie ce qui se trouve dans l'espace de travail jusqu'au premier '\n', puis on continue le traitement du texte. Pour continuer le traitement, une nouvelle ligne est chargée et va donc "écraser" les '\n' qui sont toujours présent dans l'espace de travail. + $ sed -e '/^$/ {N; D}' test.txt = Supprime les sauts de ligne + + + Explication : Pour les lignes vides, on charge la ligne suivante, on envoie ce qui se trouve dans l'espace de travail jusqu'au premier '\n', puis on continue le traitement du texte. Pour continuer le traitement, une nouvelle ligne est chargée et va donc "écraser" les '\n' qui sont toujours présents dans l'espace de travail. Lors du remplacement d'un mot par un autre, il peut survenir un problème de taille. En effet, le remplacement n'est effectué que sur le premier mot de la ligne trouvé. @@ -808,7 +819,7 @@ Lors du remplacement d'un mot par un autre, il peut survenir un problème de tai Au r[voir - On remarque que tout les 'e' et 'o' n'ont pas été remplacé.. + On remarque que tout les 'e' et 'o' n'ont pas été remplacés... Pour contrecarrer ce problème, il est possible de placer dans le script un label et de revenir dessus, comme un goto en C. Pour effectuer ce retour utilisez la commande 'b'. @@ -825,24 +836,24 @@ Pour contrecarrer ce problème, il est possible de placer dans le script un labe Au r[v[ir - Explication : Un label est placé au début des commandes. La première commande remplace le premier [eo] trouvé. La seconde retourne au label si il reste encore un [eo] dans la ligne. Une fois qu'il n'y a plus de [eo], la ligne suivant est chargée. + Explication : Un label est placé au début des commandes. La première commande remplace le premier [eo] trouvé. La seconde retourne au label si il reste encore un [eo] dans la ligne. Une fois qu'il n'y a plus de [eo], la ligne suivante est chargée. -Appliqué des actions à un fichier -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Appliquer des actions à un fichier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `awk(1)`_ [-Fs] [-v variable] [-f fichier de commandes] 'program' fichier - * -F : Spécifie les séparateurs de champs - * -v : Définie une variable utilisée à l'intérieur du programme. - * -f : Les commandes sont lu à partir d'un fichier. + * -F : Spécifie les séparateurs de champ + * -v : Définit une variable utilisée à l'intérieur du programme. + * -f : Les commandes sont lues à partir d'un fichier. -Note : awk est une commande extrement puissante, elle permet d'effectuer une multitude d'opération. Son utilisation est complexe et elle est bien détaillé sur ce site : http://www.shellunix.com/awk.html. Je vous encourage à le lire. +Note : awk est une commande extrêmement puissante, elle permet d'effectuer une multitude d'opérations. Son utilisation est complexe et elle est bien détaillée sur ce site : http://www.shellunix.com/awk.html. Je vous encourage à le lire. -Redirection nommé -^^^^^^^^^^^^^^^^^ +Redirection nommée +^^^^^^^^^^^^^^^^^^ -`mkfifo(1)`_ nom Crée un tube nommée +`mkfifo(1)`_ nom crée un tube nommé .. code-block:: console @@ -860,13 +871,13 @@ Redirection nommé Bash ---- -Tapez des commandes dans la console est inévitable lors d'opérations avancées sur un système Unix, et peut devenir très vite répétitif et fastidieux pour l'utilisateur. Le Bash est justement là pour éviter ces répétitions et automatiser certaines tâche à l'aide de scripts, qui sont des fichiers texte composés de différentes commandes Unix, lus, interprétés et exécutés par Bash. +Taper des commandes dans la console est inévitable lors d'opérations avancées sur un système Unix, et peut devenir très vite répétitif et fastidieux pour l'utilisateur. Le Bash est justement là pour éviter ces répétitions et automatiser certaines tâches à l'aide de scripts, qui sont des fichiers texte composés de différentes commandes Unix, lus, interprétés et exécutés par Bash. Premier script ^^^^^^^^^^^^^^ -Nous allons écrire un premier script bash pour présenter la manière générale de procéder avec un tel outils. Les scripts commencent toujours par la ligne ``#!/bin/bash`` qui indique à l'exécution qu'il s'agit d'un script et avec quel interpréteur le lire (ici bash). +Nous allons écrire un premier script bash pour présenter la manière générale de procéder avec un tel outil. Les scripts commencent toujours par la ligne ``#!/bin/bash`` qui indique à l'exécution qu'il s'agit d'un script et avec quel interpréteur le lire (ici bash). .. code-block:: bash @@ -889,14 +900,14 @@ Après il ne reste plus qu'à l'exécuter et observer le résultat. Les variables ^^^^^^^^^^^^^ -Bash permet l'utilisation de variables dans les scripts. Il peut s'agir de simples variables ou, de tableaux. Bash n'est pas un langage typé, des Int ou des String n'existe pas, toutes les variables sont traitées de la même façon. Pour illustrer ceci nous allons écrire le script `variables.sh <https://raw.github.com/HappyRave/SystInfo1/master/valgrind/variables.sh>`_ +Bash permet l'utilisation de variables dans les scripts. Il peut s'agir de simples variables ou de tableaux. Bash n'est pas un langage typé, les Int ou les String n'existent pas, toutes les variables sont traitées de la même façon. Pour illustrer ceci nous allons écrire le script `variables.sh <https://raw.github.com/HappyRave/SystInfo1/master/valgrind/variables.sh>`_ .. code-block:: bash #!/bin/bash bonjour='Hello, ' - #il est important de ne pas mettre d'espace autour du = + #il est important de ne pas mettre d'espaces autour du = nombre[0]=12 nombre[1]=52 @@ -904,7 +915,7 @@ Bash permet l'utilisation de variables dans les scripts. Il peut s'agir de simpl #on accède à une variable simple avec un $ devant son nom #on accède à un élément d'un tableau avec un $ devant et des {} autour echo $bonjour${nombre[*]} - #le caractère * indique qu'on veut utiliser tout les éléments du tableau (séparer + #le caractère * indique qu'on veut utiliser tous les éléments du tableau (séparés #par un espace à chaque fois) Ce script produit comme résultat @@ -920,9 +931,9 @@ Il est interressant de visiter cette page : http://michel.mauny.net/sii/variable Les structures de contrôle ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Comme dans chaque langage de programmation, bash offre les structures de contrôles habituelles telles que les boucles if, for ou encore while que nous allons démontrer maintenant. +Comme dans chaque langage de programmation, bash offre les structures de contrôle habituelles telles que les boucles if, for ou encore while que nous allons démontrer maintenant. -Comme dit précédemment, il n'y a pas de type en bash, true et false n'existe pas. Les conditions que les boucles vont utiliser seront les valeurs renvoyées par l'exécution d'une commande. Un 0 renvoyé correspond à un true, tandis que tout le reste est considéré comme un false. +Comme dit précédemment, il n'y a pas de type en bash, true et false n'existent pas. Les conditions que les boucles vont utiliser seront les valeurs renvoyées par l'exécution d'une commande. Un 0 renvoyé correspond à un true, tandis que tout le reste est considéré comme un false. Dans le but de tester ces boucles nous utiliserons un petit programme en C, `return.c <https://raw.github.com/HappyRave/SystInfo1/master/valgrind/return.c>`_, qui va renvoyer la valeur qu'il reçoit en argument. Le script de test est `structures.sh <https://raw.github.com/HappyRave/SystInfo1/master/valgrind/structures.sh>`_. @@ -931,7 +942,7 @@ Dans le but de tester ces boucles nous utiliserons un petit programme en C, `ret #!/bin/bash if ./return 0; then - #la valeur de renvoi sera 0 dans la boucle sera exécutée + #la valeur de renvoi sera 0 quand la boucle aura été exécutée echo "Hello" fi diff --git a/Outils/src/getopt.c b/Outils/src/getopt.c new file mode 100644 index 0000000000000000000000000000000000000000..6d95c88a08d7e0dfbdfb79f987e6092eff8f2d8c --- /dev/null +++ b/Outils/src/getopt.c @@ -0,0 +1,64 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* Definition et declaration de la structure des arguments*/ + +struct globalArgs_t { + int nbrThreads; /* Le nombre de threads lancés durant l'exécution*/ + char lettre; /* La lettre de réference*/ + int numInputFiles; /* Le nombre de fichiers qui vont être lus*/ + char **inputFiles; /* Les différents fichiers passés en arguments*/ +} globalArgs; + +static const char *optString = "t:l:h"; /* Les différentes options valables*/ + + +int main(int argc, char *argv[]){ + + int opt=0; + + /* Initialisation de globalArgs avant de commencer*/ + + globalArgs.nbrThreads=1; /* Le nombre de threads à exécuter par défaut est 1"*/ + globalArgs.lettre='a'; /* La lettre de réference par défaut est 'a' */ + globalArgs.numInputFiles=1; /* Il doit y avoir au minimum toujours 1 fichier input */ + globalArgs.inputFiles=NULL; + + opt=getopt(argc, argv, optString); /* On récupert la première option */ + + while(opt != -1){ /*Tant que l'option est valable (fait donc partie de optString)*/ + switch(opt){ + case 't': + globalArgs.nbrThreads=atoi(optarg); + break; + + case 'l': + globalArgs.lettre=optarg[0]; + break; + + case '?': + printf("Erreur : option non reconnue\n"); + exit(EXIT_FAILURE); + + case 'h': /*Display help*/ + + default: + /* On arrivera jamais ici*/ + break; + } + opt=getopt(argc, argv, optString); /* Prochaine option*/ + } + globalArgs.inputFiles=argv + optind; + globalArgs.numInputFiles=argc - optind; + + printf("Threads : %d , lettre : %c , nombre de fichiers : %d , nom des fichiers : ", globalArgs.nbrThreads, globalArgs.lettre, globalArgs.numInputFiles); + + int j; + for(j=0; j<globalArgs.numInputFiles; j++){ + printf(" %s ",globalArgs.inputFiles[j]); + } + printf("\n"); + + return EXIT_SUCCESS; +} diff --git a/Outils/src/gdb.c b/Outils/src/tab.c similarity index 100% rename from Outils/src/gdb.c rename to Outils/src/tab.c diff --git a/Outils/ssh.rst b/Outils/ssh.rst index da039f31a37f1365701a86e823c7766bb9070743..1409ebac7ebabed68e2ab5dcaccdb85cdc8dbf24 100644 --- a/Outils/ssh.rst +++ b/Outils/ssh.rst @@ -36,7 +36,7 @@ Le mot de passe ne servant à rien sans les clé et vice versa, on devine aisém Pour générer ces clés et choisir votre mot de passe, il suffit d'entrer la commande - .. code-block:: console + .. code-block:: none $ ssh-keygen -t rsa -C "login" # remplacer "login" par votre nom d'utilisateur diff --git a/README.md b/README.md index 6654f2f125a7167c1672b5e4c424f5affbe76e86..bf1c02ae54f5dab4a2a61af7816bed4ecbb13bb8 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ Systèmes Informatiques ====================== -Ce repository git est destiné à contenir les notes et exercices du cours de [Systèmes informatiques 1](http://www.uclouvain.be/cours-2014-LSINF1252) (C, Unix/Linux, ...) donné en deuxième année aux étudiants ingénieurs option informatique et aux étudiants en sciences informatiques de l'[UCL](http://www.uclouvain.be). Il sera mis régulièrement à jour et les étudiants sont encouragés à soumettre des bugs reports, envoyer des patches ( notamment pour la section relative aux outils) ou proposer de nouvelles questions à choix multiples. +[](https://travis-ci.com/obonaventure/SystemesInformatiques) + + +Ce repository git est destiné à contenir les notes et exercices du cours de [Systèmes informatiques 1](https://uclouvain.be/cours-2018-lsinf1252) (C, Unix/Linux, ...) donné en deuxième année aux étudiants ingénieurs option informatique et aux étudiants en sciences informatiques de l'[UCL](https://www.uclouvain.be). Il sera mis régulièrement à jour et les étudiants sont encouragés à soumettre des bugs reports, envoyer des patches ( notamment pour la section relative aux outils) ou proposer de nouvelles questions à choix multiples. Ce cours est écrit en restructured text et est distribué sous une licence creative commons -http://creativecommons.org/licenses/by-sa/3.0/fr/ +https://creativecommons.org/licenses/by-sa/3.0/fr/ -Des versions HTML, pdf et epub sont disponibles via http://sites.uclouvain.be/SystInfo +Des versions HTML, pdf et epub sont disponibles via https://sites.uclouvain.be/SystInfo Compilation ----------- -Les notes sont écrites en [restructured text](http://docutils.sourceforge.net/rst.html) et peuvent être transformées en un document au format HTML, epub ou PDF en utilisant le logiciel [sphinx](http://sphinx-doc.org). Pour faciliter cette compilation, une configuration [vagrant](https://www.vagrantup.com) est reprise dans le fichier [Vagrantfile](https://github.com/obonaventure/SystemesInformatiques/tree/master/Vagrantfile) se trouvant à la racine du projet. [Vagrant](https://www.vagrantup.com) est un logiciel fonctionnant sur Linux, Windows et MacOS qui permet d'automatiser et de faciliter la création de machines virtuelles supportées notamment par [Virtualbox](https://www.virtualbox.org). +Les notes sont écrites en [restructured text](http://docutils.sourceforge.net/rst.html) et peuvent être transformées en un document au format HTML, epub ou PDF en utilisant le logiciel [sphinx](https://sphinx-doc.org). Pour faciliter cette compilation, une configuration [vagrant](https://www.vagrantup.com) est reprise dans le fichier [Vagrantfile](https://github.com/obonaventure/SystemesInformatiques/tree/master/Vagrantfile) se trouvant à la racine du projet. [Vagrant](https://www.vagrantup.com) est un logiciel fonctionnant sur Linux, Windows et MacOS qui permet d'automatiser et de faciliter la création de machines virtuelles supportées notamment par [Virtualbox](https://www.virtualbox.org). Pour démarrer votre environnement [Vagrant](https://www.vagrantup.com), commencez par installer [Vagrant](https://www.vagrantup.com) et [Virtualbox](https://www.virtualbox.org). [Vagrant](https://www.vagrantup.com) utilise le [Vagrantfile](https://github.com/obonaventure/SystemesInformatiques/tree/master/Vagrantfile) pour créer les machines virtuelles. Ce dernier marque le dossier racine du projet et décrit le type de machine ainsi que les dépendances logicielles nécessaires au projet. @@ -28,7 +31,7 @@ Finalement, lorsque que vous avez terminé de travailler sur le projet, vous pou Comment créer de nouvelles questions à choix multiples ------------------------------------------------------ -Une des améliorations récentes aux notes du cours reprises sur ce repository git est le support de questions à choix multiples. Ces questions à choix multiples sont écrites grâce à une petite extension à [http://www.sphinx-doc.org](sphinx) qui est intégrée au projet. Plusieurs dizaines de questions à choix multiples ont déjà étés écrites et les étudiants sont invités à proposer de nouvelles questions en s'appuyant sur les difficultés qu'ils ont rencontré en préparant les travaux pratiques du cours ou en révisant la théorie. +Une des améliorations récentes aux notes du cours reprises sur ce repository git est le support de questions à choix multiples. Ces questions à choix multiples sont écrites grâce à une petite extension à [https://www.sphinx-doc.org](sphinx) qui est intégrée au projet. Plusieurs dizaines de questions à choix multiples ont déjà étés écrites et les étudiants sont invités à proposer de nouvelles questions en s'appuyant sur les difficultés qu'ils ont rencontré en préparant les travaux pratiques du cours ou en révisant la théorie. Une bonne question à choix multiples doit répondre à plusieurs critères : diff --git a/Theorie/C/S3-src/malloc.c b/Theorie/C/S3-src/malloc.c index fbf967668493548545ddd05867b5b404ed61d44b..3474c744e2f24fa3c9c20641a48dcb1d8360125c 100644 --- a/Theorie/C/S3-src/malloc.c +++ b/Theorie/C/S3-src/malloc.c @@ -52,3 +52,4 @@ int main(int argc, char *argv[]) { return(EXIT_SUCCESS); } +///BBB diff --git a/Theorie/C/datatypes.rst b/Theorie/C/datatypes.rst index c727873ce872f0bdee4431cb3e0c5dd279ce5de0..518d66bc1d891ec126f288eda43f7303356b361f 100644 --- a/Theorie/C/datatypes.rst +++ b/Theorie/C/datatypes.rst @@ -7,7 +7,7 @@ Types de données ================ Durant la première semaine, nous avons abordé quelques types de -données de base dont les ``int`` et les ``char``. Pour utiliser ces types de données à bon escient, il est important de comprendre en détails la façon dont ils sont supportés par le compilateur et leurs limitations. Celles-ci dépendent souvent de leur représentation en mémoire et durant cette semaine nous allons commencer à analyser de façon plus détaillée comment la mémoire d'un ordinateur est structurée. +données de base dont les ``int`` et les ``char``. Pour utiliser ces types de données à bon escient, il est important de comprendre en détail la façon dont ils sont supportés par le compilateur et leurs limitations. Celles-ci dépendent souvent de leur représentation en mémoire et durant cette semaine nous allons commencer à analyser de façon plus détaillée comment la mémoire d'un ordinateur est structurée. @@ -22,12 +22,12 @@ types de nombres entiers : - les nombres entiers signés (``int`` notamment en C) - les nombres entiers non-signés (``unsigned int`` notamment en C) -Une séquence de :math:`n` bits :math:`b_0 ... b_i ... b_n` peut représenter le +Une séquence de :math:`n` bits :math:`b_0 ... b_i ... b_{n-1}` peut représenter le nombre entier :math:`\sum_{i=0}^{n-1} b_i \times 2^i`. Par convention, le bit -:math:`b_n`, associé au facteur du plus grand indice :math:`2^n`, est appelé le +:math:`b_{n-1}`, associé au facteur du plus grand indice :math:`2^{n-1}`, est appelé le :term:`bit de poids fort` tandis que le bit :math:`b_0`, associé à :math:`2^0`, est appelé le :term:`bit de poids faible`. Les suites de bits sont communément -écrites dans l'ordre descendant des indices :math:`b_n ... b_i ... b_0`. A titre +écrites dans l'ordre descendant des indices :math:`b_{n-1} ... b_i ... b_0`. À titre d'exemple, la suite de bits ``0101`` correspond à l'entier non signé représentant la valeur cinq. Le bit de poids fort (resp. faible) de cette séquence de quatre bits (ou :term:`nibble`) est ``0`` (resp. ``1``). La table ci-dessous reprend les @@ -56,9 +56,9 @@ binaire octal hexadécimal décimal .. todo cafe, deadbeef adresses ipv6 http://www.qa.com/about-qa/blogs/2011/november/ipv6-the-return-of-badbeef-and-5adcafe/ -Ecrire une séquence de bits sous la forme d'une suite de +Écrire une séquence de bits sous la forme d'une suite de ``0`` et de ``1`` peut s'avérer fastidieux. La représentation décimale -traditionnelle n'est pas pratique non plus car il faut un ou deux +traditionnelle n'est pas pratique (optimale) non plus car il faut un ou deux chiffres pour représenter une séquence de quatre bits (ou :term:`nibble`) en fonction de la valeur de ces bits. En pratique, de nombreux systèmes informatiques utilisent une représentation hexadécimale pour afficher des séquences @@ -186,7 +186,7 @@ binaire décimal signé En C, les types de données utilisés pour représenter des entiers sont signés par défaut. Ils ont la même taille que leurs équivalents -non-signés et sont repris dans la table ci-dessous. +non signés et sont repris dans la table ci-dessous. ============================= =================================================== Type Explication @@ -270,8 +270,8 @@ Outre les nombres entiers, les systèmes informatiques doivent aussi pouvoir manipuler des nombres réels. Ceux-ci sont également représentés sous la forme d'une séquence fixe de bits. Il existe deux formes de représentation pour les nombres réels : - - la représentation en :term:`simple précision` dans laquelle le nombre réel est stocké sous la forme d'une séquence de 32 bits - - la représentation en :term:`double précision` dans laquelle le nombre réel est stocké sous la forme d'une séquence de 64 bits + - la représentation en :term:`simple précision` dans laquelle le nombre réel est stocké sous la forme d'une séquence de 32 bits; + - la représentation en :term:`double précision` dans laquelle le nombre réel est stocké sous la forme d'une séquence de 64 bits. La plupart des systèmes informatiques qui permettent de manipuler des nombres réels utilisent le standard IEEE-754. Un nombre réel est @@ -279,14 +279,14 @@ représenté en virgule flottante et la séquence de bits correspondante est décomposée en trois parties [#fexemple]_ : - le bit de poids fort indique le signe du nombre. Par convention, ``0`` est utilisé pour les nombres positifs et ``1`` pour les nombres négatifs. - - `e` bits sont réservés pour stocker l'exposant [#fexposant]_ - - les `f` bits de poids faible servent à stocker la partie fractionnaire du nombre réel + - `e` bits sont réservés pour stocker l'exposant [#fexposant]_. + - Les `f` bits de poids faible servent à stocker la partie fractionnaire du nombre réel. .. figure:: /C/svg/Float_example.png :align: center :scale: 100 - Exemple de nombre en virgule flottante (simple précision) (source : wikipedia) + Exemple de nombre en virgule flottante (simple précision). (source : Wikipedia) En simple (resp. double) précision, `8` (resp. `11`) bits sont utilisés pour stocker l'exposant et `23` (resp. `52`) bits pour la partie @@ -297,7 +297,7 @@ cours, mais il est important de noter deux propriétés importantes de la notation en virgule flottante utilisée actuellement. Ces deux propriétés s'appliquent de la même façon à la simple qu'à la double précision. - - une représentation en virgule flottante sur `n` bits ne permet jamais de représenter plus de :math:`2^n` nombres réels différents + - une représentation en virgule flottante sur `n` bits ne permet jamais de représenter plus de :math:`2^n` nombres réels différents; - les représentations en virgule flottante privilégient les nombres réels compris dans l'intervalle :math:`[-1,1]`. On retrouve autant de nombres réels représentables dans cet intervalle que de nombres dont la valeur absolue est supérieure à `1`. En C, ces nombres en virgule flottante sont représentés en utilisant @@ -333,7 +333,7 @@ Un tableau à une dimension peut s'utiliser avec une syntaxe similaire à celle :start-after: ///CCC :end-before: ///DDD -Le langage C permet aussi la manipulation de matrices carrées ou rectangulaires qui sont composées d'éléments d'un même type. L'exemple ci-dessous calcule l'élément minimum d'une matrice rectangulaire. Il utilise la constante ``FLT_MAX`` qui correspond au plus grand nombre réel représentable avec un ``float`` qui est définie dans `float.h`_. +Le langage C permet aussi la manipulation de matrices carrées ou rectangulaires qui sont composées d'éléments d'un même type. L'exemple ci-dessous calcule l'élément minimum d'une matrice rectangulaire. Il utilise la constante ``FLT_MAX`` qui correspond au plus grand nombre réel représentable avec un ``float`` et qui est définie dans `float.h`_. .. literalinclude:: /C/S2-src/array.c :language: c @@ -359,7 +359,7 @@ d'ordinateurs et a été utilisé comme standard pour de nombreuses applications et notamment sur Internet :rfc:`20`. La table de caractères ASCII définit une correspondance entre des séquences de bits et des caractères. :rfc:`20` contient la table des caractères -ASCII représentés sur 7 bits. A titre d'exemple, le chiffre `0` +ASCII représentés sur 7 bits. À titre d'exemple, le chiffre `0` correspond à l'octet `0b00110000` et le chiffre `9` à l'octet `0b00111001`. La lettre `a` correspond à l'octet `0b01100001` et la lettre `A` à l'octet `0b01000001`. @@ -373,7 +373,7 @@ type ``char`` que nous avons déjà évoqué. Concernant le type ``char``, il est utile de noter qu'un ``char`` est considéré en C comme correspondant à un entier. Cela implique qu'il est possible de faire des manipulations numériques sur les -caractères. A titre d'exemple, une fonction `toupper(3)`_ permettant +caractères. À titre d'exemple, une fonction `toupper(3)`_ permettant de transformer un caractère représentant une minuscule dans le caractère représentant la majuscule correspondante peut s'écrire : @@ -401,7 +401,7 @@ informatiques. Il est cependant important que vous soyez conscient de cette problématique pour pouvoir la prendre en compte lorsque vous développerez des applications qui doivent traiter du texte dans différentes langues. -A titre d'exemple, la fonction `toupper(3)`_ qui est implémentée dans +À titre d'exemple, la fonction `toupper(3)`_ qui est implémentée dans les versions actuelles de Linux est nettement plus complexe que celle que nous avons vue ci-dessus. Tout d'abord, la fonction `toupper(3)`_ prend comme argument un ``int`` et non un ``char``. Cela lui permet @@ -445,7 +445,7 @@ plus tard ce choix a de nombreuses conséquences. Cette particularité permet d'implémenter facilement des fonctions de manipulation de chaînes de -caractères. A titre d'exemple, la fonction ci-dessous calcule +caractères. À titre d'exemple, la fonction ci-dessous calcule la longueur d'une chaîne de caractères. .. literalinclude:: /C/S2-src/strlen.c @@ -466,7 +466,7 @@ sur la façon dont un programme manipule un tableau. En C, il est tout printf("%c", name[-1]); En Java, tous les accès au tableau ``name`` en dehors de la zone -mémoire réservée provoqueraient une ``ArrayOutOfBoundException``. En +mémoire réservée provoqueraient une ``ArrayIndexOutOfBoundsException``. En C, il n'y a pas de mécanisme d'exception et le langage présuppose que lorsqu'un programmeur écrit ``name[i]``, il a la garantie que la valeur ``i`` sera telle qu'il accédera bien à un élément valide du tableau @@ -482,7 +482,7 @@ Les pointeurs ------------- Une différence majeure entre le C et la plupart des langages de -programmation actuels est que le C est proche de la machine et permet +programmation actuels est que le C est proche de la machine (langage de bas niveau) et permet au programmeur d'interagir directement avec la mémoire où les données qu'un programme manipule sont stockées. En Java, un programme peut créer autant d'objets qu'il souhaite (ou presque [#fstackjava]_). Ceux-ci sont @@ -504,8 +504,8 @@ permettant de stocker de l'information est identifiée par une :term:`adresse`. La mémoire peut être vue comme l'implémentation de deux fonctions C : - - ``data read(addr)`` est une fonction qui sur base - d'une adresse retourne la valeur stockée à cette adresse + - ``data read(addr)`` est une fonction qui, sur base + d'une adresse, retourne la valeur stockée à cette adresse. - ``void write(addr, data)`` est une fonction qui écrit la donnée ``data`` à l'adresse ``addr`` en mémoire. @@ -513,7 +513,7 @@ Ces adresses sont stockées sur un nombre fixe de bits qui dépend en général de l'architecture du microprocesseur. Les valeurs les plus courantes aujourd'hui sont `32` et `64`. Par convention, les adresses sont représentées sous la forme d'entiers -non-signés. Sur la plupart des architectures de processeurs, une +non signés. Sur la plupart des architectures de processeurs, une adresse correspond à une zone mémoire permettant de stocker un octet. Lorsque nous utiliserons une représentation graphique de la mémoire, nous placerons toujours les adresses numériquement basses en bas de la @@ -641,9 +641,9 @@ En mémoire, ce tableau est stocké en utilisant trois mots consécutifs de 32 b .. code-block:: console - 1020304 est a l'adresse 0x7fff5fbff750 - 5060708 est a l'adresse 0x7fff5fbff754 - 90A0B0C est a l'adresse 0x7fff5fbff758 + 1020304 est à l'adresse 0x7fff5fbff750 + 5060708 est à l'adresse 0x7fff5fbff754 + 90A0B0C est à l'adresse 0x7fff5fbff758 La même sortie est produite avec le fragment de programme suivant qui utilise un pointeur. @@ -653,7 +653,7 @@ La même sortie est produite avec le fragment de programme suivant qui utilise u :start-after: ///EEE :end-before: ///FFF -Ce fragment de programme est l'occasion de réfléchir sur la façon dont le C évalue les expressions qui contiennent des pointeurs. La première est l'assignation ``ptr=tab``. Lorsque ``tab`` est déclaré par la ligne ``unsigned int tab[3]``, le compilateur considère que ``tab`` est une constante qui contiendra toujours l'adresse du premier élément du tableau. Il faut noter que puisque ``tab`` est considéré comme une constante, il est interdit d'en modifier la valeur en utilisant une assignation comme ``tab=tab+1``. Le pointeur ``ptr``, par contre correspond à une zone mémoire qui contient une adresse. Il est tout à fait possible d'en modifier la valeur. Ainsi, l'assignation ``ptr=tab`` (ou ``ptr=&(tab[0])``) place dans ``ptr`` l'adresse du premier élément du tableau. Les pointeurs peuvent aussi être modifiés en utilisant des expressions arithmétiques. +Ce fragment de programme est l'occasion de réfléchir sur la façon dont le C évalue les expressions qui contiennent des pointeurs. La première est l'assignation ``ptr=tab``. Lorsque ``tab`` est déclaré par la ligne ``unsigned int tab[3]``, le compilateur considère que ``tab`` est une constante qui contiendra toujours l'adresse du premier élément du tableau. Il faut noter que puisque ``tab`` est considéré comme une constante, il est interdit d'en modifier la valeur en utilisant une assignation comme ``tab=tab+1``. Le pointeur ``ptr``, par contre, correspond à une zone mémoire qui contient une adresse. Il est tout à fait possible d'en modifier la valeur. Ainsi, l'assignation ``ptr=tab`` (ou ``ptr=&(tab[0])``) place dans ``ptr`` l'adresse du premier élément du tableau. Les pointeurs peuvent aussi être modifiés en utilisant des expressions arithmétiques. .. code-block:: c @@ -661,7 +661,7 @@ Ce fragment de programme est l'occasion de réfléchir sur la façon dont le C ptr++; // ligne 2 ptr = ptr - 2; // ligne 3 -Après l'exécution de la première ligne, ``ptr`` va contenir l'adresse de l'élément ``1`` du tableau ``tab`` (c'est-à -dire ``&(tab[1])``). Ce résultat peut surprendre car si l'élément ``tab[0]`` se trouve à l'adresse ``0x7fff5fbff750`` c'est cette adresse qui est stocké dans la zone mémoire correspondant au pointeur ``ptr``. On pourrait donc s'attendre à ce que l'expression ``ptr+1`` retourne plutôt la valeur ``0x7fff5fbff751``. Il n'est en rien. En C, lorsque l'on utilise des calculs qui font intervenir des pointeurs, le compilateur prend en compte le type du pointeur qui est utilisé. Comme ``ptr`` est de type ``unsigned int*``, il pointe toujours vers une zone mémoire permettant de stocker un entier non-signé sur 32 bits. L'expression ``ptr+1`` revient en fait à calculer la valeur ``ptr+sizeof(unsigned int)`` et donc ``ptr+1`` correspondra à l'adresse ``0x7fff5fbff754``. Pour la même raison, l'exécution de la deuxième ligne placera l'adresse ``0x7fff5fbff758`` dans ``ptr``. Enfin, la dernière ligne calculera ``0x7fff5fbff758-2*sizeof(unsigned int)`` ce qui correspond à ``0x7fff5fbff750``. +Après l'exécution de la première ligne, ``ptr`` va contenir l'adresse de l'élément ``1`` du tableau ``tab`` (c'est-à -dire ``&(tab[1])``). Ce résultat peut surprendre car si l'élément ``tab[0]`` se trouve à l'adresse ``0x7fff5fbff750`` c'est cette adresse qui est stockée dans la zone mémoire correspondant au pointeur ``ptr``. On pourrait donc s'attendre à ce que l'expression ``ptr+1`` retourne plutôt la valeur ``0x7fff5fbff751``. Il n'en est rien. En C, lorsque l'on utilise des calculs qui font intervenir des pointeurs, le compilateur prend en compte le type du pointeur qui est utilisé. Comme ``ptr`` est de type ``unsigned int*``, il pointe toujours vers une zone mémoire permettant de stocker un entier non signé sur 32 bits. L'expression ``ptr+1`` revient en fait à calculer la valeur ``ptr+sizeof(unsigned int)`` et donc ``ptr+1`` correspondra à l'adresse ``0x7fff5fbff754``. Pour la même raison, l'exécution de la deuxième ligne placera l'adresse ``0x7fff5fbff758`` dans ``ptr``. Enfin, la dernière ligne calculera ``0x7fff5fbff758-2*sizeof(unsigned int)``, ce qui correspond à ``0x7fff5fbff750``. Il est intéressant pour terminer cette première discussion de l'arithmétique des pointeurs, de considérer l'exécution du fragment de code ci-dessous. @@ -676,10 +676,10 @@ L'exécution de ce fragment de code produit une sortie qu'il est intéressant d' .. code-block:: console ptr_char contient 0x7fff5fbff750 - 4 est a l'adresse 0x7fff5fbff750 - 3 est a l'adresse 0x7fff5fbff751 - 2 est a l'adresse 0x7fff5fbff752 - 1 est a l'adresse 0x7fff5fbff753 + 4 est à l'adresse 0x7fff5fbff750 + 3 est à l'adresse 0x7fff5fbff751 + 2 est à l'adresse 0x7fff5fbff752 + 1 est à l'adresse 0x7fff5fbff753 Tout d'abord, l'initialisation du pointeur ``ptr_char`` a bien stocké dans ce pointeur l'adresse en mémoire du premier élément du tableau. Ensuite, comme ``ptr_char`` est un pointeur de type ``unsigned char *``, l'expression ``*ptr_char`` a retourné la valeur de l'octet se trouvant à l'adresse ``0x7fff5fbff750``. L'incrémentation du pointeur ``ptr_char`` s'est faite en respectant l'arithmétique des pointeurs. Comme ``sizeof(unsigned char)`` retourne ``1``, la valeur stockée dans ``ptr_char`` a été incrémentée d'une seule unité par l'instruction ``ptr_char++``. En analysant les quatre ``unsigned char`` se trouvant aux adresses ``0x7fff5fbff750`` à ``0x7fff5fbff753``, on retrouve bien l'entier ``0x01020304`` qui avait été placé dans ``tab[0]``. @@ -689,7 +689,7 @@ Tout d'abord, l'initialisation du pointeur ``ptr_char`` a bien stocké dans ce p Les structures -------------- -Outre les types de données décrits ci-dessus, les programmes informatiques doivent souvent pouvoir manipuler des données plus complexes. A titre d'exemples, un programme de calcul doit pouvoir traiter des nombres complexes, un programme de gestion des étudiants doit traiter des fiches d'étudiants avec nom, prénom, numéro de matricule, ... Dans les langages orientés objets comme Java, cela se fait en encapsulant des données de différents types avec les méthodes permettant leur traitement. C n'étant pas un langage orienté objet, il ne permet pas la création d'objets et de méthodes directement associées. Par contre, C permet de construire des types de données potentiellement complexes. +Outre les types de données décrits ci-dessus, les programmes informatiques doivent souvent pouvoir manipuler des données plus complexes. À titre d'exemples, un programme de calcul doit pouvoir traiter des nombres complexes, un programme de gestion des étudiants doit traiter des fiches d'étudiants avec nom, prénom, numéro de matricule,... Dans les langages orientés objet comme Java, cela se fait en encapsulant des données de différents types avec les méthodes permettant leur traitement. C n'étant pas un langage orienté objet, il ne permet pas la création d'objets et de méthodes directement associées. Par contre, C permet de construire des types de données potentiellement complexes. C permet la définition de structures qui combinent différents types de données simples ou structurés. Contrairement aux langages orientés objet, il n'y a pas de méthode directement associée aux structures qui sont définies. Une structure est uniquement un type de données. Voici quelques exemples de structures simples en C. @@ -701,7 +701,7 @@ C permet la définition de structures qui combinent différents types de donnée Le premier bloc définit une structure dénommée ``coord`` qui contient trois entiers baptisés ``x``, ``y`` et ``z``. Dans une structure, chaque élément est identifié par son nom et il est possible d'y accéder directement. La variable ``point`` est de type ``struct coord`` et son élément ``x`` est initialisé à la valeur ``1`` tandis que son élément ``z`` est initialisé à la valeur ``3``. La variable ``p`` est également de type ``struct coord`` mais elle n'est pas explicitement initialisée lors de sa déclaration. -La structure ``struct fract`` définit une fraction qui est composée de deux entiers qui sont respectivement le numérateur et le dénominateur. La structure ``struct student`` définit elle un type de données qui comprend un numéro de matricule et deux chaînes de caractères. +La structure ``struct fract`` définit une fraction qui est composée de deux entiers qui sont respectivement le numérateur et le dénominateur. La structure ``struct student``, elle, définit un type de données qui comprend un numéro de matricule et deux chaînes de caractères. Les structures permettent de facilement regrouper des données qui sont logiquement reliées entre elles et doivent être manipulées en même temps. C permet d'accéder facilement à un élément d'une structure en utilisant l'opérateur '``.``'. Ainsi, la structure ``point`` dont nous avons parlé ci-dessus aurait pu être initialisée par les trois expressions ci-dessous : @@ -714,7 +714,7 @@ Les structures permettent de facilement regrouper des données qui sont logiquem Dans les premières versions du langage C, une structure devait nécessairement contenir uniquement des données qui ont une taille fixe, c'est-à -dire des nombres, des caractères, des pointeurs ou des tableaux de taille fixe. Il n'était pas possible de stocker des tableaux de taille variable comme une chaîne de caractères ``char []``. Les compilateurs récents [C99]_ permettent de supporter des tableaux flexibles à l'intérieur de structures. Nous ne les utiliserons cependant pas dans le cadre de ce cours. -Les structures sont utilisées dans différentes librairies et appels systèmes sous Unix et Linux. Un exemple classique est la gestion du temps sur un système Unix. Un système informatique contient généralement une horloge dite `temps-réel` qui est en pratique construite autour d'un cristal qui oscille à une fréquence fixée. Ce cristal est piloté par un circuit électronique qui compte ses oscillations, ce qui permet de mesurer le passage du temps. Le système d'exploitation utilise cette horloge `temps réel` pour diverses fonctions et notamment la mesure du temps du niveau des applications. +Les structures sont utilisées dans différentes librairies et appels système sous Unix et Linux. Un exemple classique est la gestion du temps sur un système Unix. Un système informatique contient généralement une horloge dite `temps-réel` qui est en pratique construite autour d'un cristal qui oscille à une fréquence fixée. Ce cristal est piloté par un circuit électronique qui compte ses oscillations, ce qui permet de mesurer le passage du temps. Le système d'exploitation utilise cette horloge `temps réel` pour diverses fonctions et notamment la mesure du temps du niveau des applications. Un système de type Unix maintient différentes structures qui sont associées à la mesure du temps [#ftimelibc]_. La première sert à mesurer le nombre de secondes et de microsecondes qui se sont écoulées depuis le 1er janvier 1970. Cette structure, baptisée ``struct timeval`` est définie dans `sys/time.h`_ comme suit : @@ -725,7 +725,7 @@ Un système de type Unix maintient différentes structures qui sont associées suseconds_t tv_usec; /* and microseconds */ }; -Cette structure est utilisée par des appels systèmes tels que `gettimeofday(2)`_ pour notamment récupérer l'heure courante ou les appels de manipulation de timers tels que `getitimer(2)`_ / `setitimer(2)`_. Elle est aussi utilisée par la fonction `time(3posix)`_ de la librairie standard et est très utile pour mesurer les performances d'un programme. +Cette structure est utilisée par des appels système tels que `gettimeofday(2)`_ pour notamment récupérer l'heure courante ou les appels de manipulation de timers tels que `getitimer(2)`_ / `setitimer(2)`_. Elle est aussi utilisée par la fonction `time(3posix)`_ de la librairie standard et est très utile pour mesurer les performances d'un programme. Les structures sont également fréquemment utilisées pour représenter des formats de données spéciaux sur disque comme le format des répertoires [#fdirent]_ ou les formats de paquets qui sont échangés sur le réseau [#freseau]_. @@ -742,7 +742,7 @@ Les types ``Entier`` et ``int`` peuvent être utilisés de façon interchangeabl .. note:: ``typedef`` en pratique - Le renommage de types de données a des avantages et des inconvénients dont il faut être conscient pour pouvoir l'utiliser à bon escient. L'utilisation de ``typedef`` peut faciliter la lecture et la portabilité de certains programmes. Lorsqu'un ``typedef`` est associé à une structure, cela facilite la déclaration de variables de ce type et permet le cas échéant de modifier la structure de données ultérieurement sans pour autant devoir modifier l'ensemble du programme. Cependant, contrairement aux langages orientés objet, des méthodes ne sont pas directement associées aux structures et la modification d'une structure oblige souvent à vérifier toutes les fonctions qui utilisent cette structure. L'utilisation de ``typedef`` permet de clarifier le rôle de certains types de données ou valeurs de retour de fonctions. A titre d'exemple, l'appel système `read(2)`_ qui permet notamment de lire des données dans un fichier retourne le nombre d'octets qui ont été lus après chaque appel. Cette valeur de retour est de type ``ssize_t``. L'utilisation de ces types permet au compilateur de vérifier que les bons types de données sont utilisés lors des appels de fonctions. + Le renommage de types de données a des avantages et des inconvénients dont il faut être conscient pour pouvoir l'utiliser à bon escient. L'utilisation de ``typedef`` peut faciliter la lecture et la portabilité de certains programmes. Lorsqu'un ``typedef`` est associé à une structure, cela facilite la déclaration de variables de ce type et permet le cas échéant de modifier la structure de données ultérieurement sans pour autant devoir modifier l'ensemble du programme. Cependant, contrairement aux langages orientés objet, des méthodes ne sont pas directement associées aux structures et la modification d'une structure oblige souvent à vérifier toutes les fonctions qui utilisent cette structure. L'utilisation de ``typedef`` permet de clarifier le rôle de certains types de données ou valeurs de retour de fonctions. À titre d'exemple, l'appel système `read(2)`_ qui permet notamment de lire des données dans un fichier retourne le nombre d'octets qui ont été lus après chaque appel. Cette valeur de retour est de type ``ssize_t``. L'utilisation de ces types permet au compilateur de vérifier que les bons types de données sont utilisés lors des appels de fonctions. ``typedef`` est souvent utilisé pour avoir des identifiants de type de données plus court. Par exemple, il est très courant d'abrévier les types ``unsigned`` comme ci-dessous. @@ -864,7 +864,7 @@ Ces deux fonctions peuvent être utilisées par le fragment de code ci-dessous : De nombreux programmeurs débutants ignorent souvent les warnings émis par le compilateur et se contentent d'avoir un programme compilable. C'est la source de nombreuses erreurs et de nombreux problèmes. Dans l'exemple ci-dessus, l'exécution de l'appel ``plusun(vecteur,N)`` provoquera une tentative d'accès à la mémoire dans une zone qui n'est pas allouée au processus. Dans ce cas, la tentative d'accès est bloquée par le système et provoque l'arrêt immédiat du programme sur une :term:`segmentation fault`. Dans d'autres cas, des erreurs plus subtiles mais du même type ont provoqué des problèmes graves de sécurité dans des programmes écrits en langage C. Nous y reviendrons ultérieurement. -Pour terminer, mentionnons que les fonctions écrites en C peuvent utiliser des structures et des pointeurs vers des structures comme arguments. Elles peuvent aussi retourner des structures comme résultat. Ceci est illustré par deux variantes de fonctions permettant d'initialiser une fraction et de déterminer si deux fractions sont égales [#fegal]_ +Pour terminer, mentionnons que les fonctions écrites en C peuvent utiliser des structures et des pointeurs vers des structures comme arguments. Elles peuvent aussi retourner des structures comme résultat. Ceci est illustré par deux variantes de fonctions permettant d'initialiser une fraction et de déterminer si deux fractions sont égales [#fegal]_. .. literalinclude:: /C/S2-src/struct.c :encoding: utf-8 @@ -874,7 +874,7 @@ Pour terminer, mentionnons que les fonctions écrites en C peuvent utiliser des Considérons d'abord les fonctions ``init`` et ``equal``. ``init`` est une fonction qui construit une structure sur base d'arguments entiers et retourne la valeur construite. ``equal`` quant à elle reçoit comme arguments les valeurs de deux structures. Elle peut accéder à tous les éléments des structures passées en argument. Comme ces structures sont passées par valeur, toute modification aux éléments de la structure est locale à la fonction ``equal`` et n'est pas répercutée sur le code qui a appelé la fonction. -Les fonctions ``initptr`` et ``equalptr`` utilisent toutes les deux des pointeurs vers des ``struct fraction`` comme arguments. Ce faisant, elles ne peuvent modifier la valeur de ces pointeurs puisqu'ils sont passés comme valeur. Par contre, les deux fonctions peuvent bien entendu modifier les éléments de la structure qui se trouvent dans la zone de mémoire pointée par le pointeur. C'est ce que ``initptr`` fait pour initialiser la structure. ``equalptr`` par contre se contente d'accéder aux éléments des structures passées en argument sans les modifier. Le fragment de code ci-dessous illustre comment ces fonctions peuvent être utilisées en pratique. +Les fonctions ``initptr`` et ``equalptr`` utilisent toutes les deux des pointeurs vers des ``struct fraction`` comme arguments. Ce faisant, elles ne peuvent modifier la valeur de ces pointeurs puisqu'ils sont passés comme valeurs. Par contre, les deux fonctions peuvent bien entendu modifier les éléments de la structure qui se trouvent dans la zone de mémoire pointée par le pointeur. C'est ce que ``initptr`` fait pour initialiser la structure. ``equalptr`` par contre se contente d'accéder aux éléments des structures passées en argument sans les modifier. Le fragment de code ci-dessous illustre comment ces fonctions peuvent être utilisées en pratique. .. literalinclude:: /C/S2-src/struct.c :encoding: utf-8 @@ -967,7 +967,7 @@ L'opération XOR joue un rôle important dans certaines applications. La plupart :start-after: ///AAA :end-before: ///BBB -.. note:: Ne pas confondre expressions logiques et opérateurs binaires +.. note:: Ne pas confondre expressions logiques et opérateurs binaires. En C, les symboles utilisés pour les expressions logiques (``||`` et ``&&``) sont très proches de ceux utilisés pour représenter les opérateurs binaires (`|` et `&`). Il arrive parfois qu'un développeur confonde ``&`` avec ``&&``. Malheureusement, le compilateur ne peut pas détecter une telle erreur car dans les deux cas le résultat attendu est généralement du même type. @@ -978,14 +978,14 @@ L'opération XOR joue un rôle important dans certaines applications. La plupart 0b0100 | 0b0101 = 0b0101 0b0100 || 0b0101 = 0b0001 - Un autre point important à mentionner concernant les expressions logiques est qu'en C celles-ci sont évaluées de gauche à droite. Cela implique que dans l'expression ``( expr1 && expr2 )``, le compilateur C va d'abord évaluer l'expression ``expr1``. Si celle-ci est évaluée à la valeur ``0``, la seconde expression ne sera pas évaluée. Cela peut être très utile lorsque l'on doit exécuter du code si un pointeur est non ``NULL`` et qu'il pointe vers une valeur donnée. Dans ce cas, la condition sera du type ``((ptr != NULL) && (ptr->den > 0))``. + Un autre point important à mentionner concernant les expressions logiques est qu'en C celles-ci sont évaluées de gauche à droite. Cela implique que dans l'expression ``( expr1 && expr2 )``, le compilateur C va d'abord évaluer l'expression ``expr1``. Si celle-ci est évaluée à la valeur ``0``, la seconde expression ne sera pas évaluée. Cela peut être très utile lorsque l'on doit exécuter du code si un pointeur est non-``NULL`` et qu'il pointe vers une valeur donnée. Dans ce cas, la condition sera du type ``((ptr != NULL) && (ptr->den > 0))``. Pour terminer, le langage C supporte des expressions permettant le décalage à gauche ou à droite à l'intérieur d'une suite de bits non signée. - - ``a = n >> B`` décale les bits représentants ``n`` de ``B`` bits vers la droite et place le résultat dans la variable ``a`` - - ``a = n << B`` décale les bits représentants ``n`` de ``B`` bits vers la gauche et place le résultat dans la variable ``a`` + - ``a = n >> B`` décale les bits représentants ``n`` de ``B`` bits vers la droite et place le résultat dans la variable ``a``. + - ``a = n << B`` décale les bits représentants ``n`` de ``B`` bits vers la gauche et place le résultat dans la variable ``a``. -Ces opérations de décalage permettent différentes manipulations de bits. A titre d'exemple, la fonction ``int2bin`` utilise à la fois des décalages et des masques pour calculer la représentation binaire d'un entier non-signé et la placer dans une chaîne de caractères. +Ces opérations de décalage permettent différentes manipulations de bits. À titre d'exemple, la fonction ``int2bin`` utilise à la fois des décalages et des masques pour calculer la représentation binaire d'un entier non signé et la placer dans une chaîne de caractères. .. literalinclude:: /C/S2-src/exprbin.c :encoding: utf-8 @@ -1007,10 +1007,6 @@ Ces opérations de décalage permettent différentes manipulations de bits. A ti .. [#fdirent] Voir notamment `fs(5)`_ pour des exemples relatifs aux systèmes de fichiers. Une analyse détaillée des systèmes de fichiers sort du cadre de ce cours. -.. [#freseau] Parmi les exemples simples, on peut citer la structure ``struct ipv6hdr`` qui correspond à l'entête IPv6 et est définie dans `linux/ipv6.h`_ +.. [#freseau] Parmi les exemples simples, on peut citer la structure ``struct ipv6hdr`` qui correspond à l'entête IPv6 et est définie dans `linux/ipv6.h`_. .. [#fegal] Cette définition de l'égalité entre fractions suppose que les fractions à comparer sont sous forme irréductible. Le lecteur est invité à écrire la fonction générale permettant de tester l'égalité entre fractions réductibles. - - - - diff --git a/Theorie/C/intro-C.rst b/Theorie/C/intro-C.rst index a976cbd6bf74e6cb2998307b3341734bf6b1bb47..f06c86120d594686fb3b23eccb0414bd79c7d5d7 100644 --- a/Theorie/C/intro-C.rst +++ b/Theorie/C/intro-C.rst @@ -42,7 +42,7 @@ Lorsqu'il est exécuté, le programme `hello` affiche simplement le message suiv .. code-block:: console $ ./hello - hello, world + Hello, world! $ Même si ce programme est très simple, il illustre quelques concepts de base en langage C. Tout d'abord comme en Java, les compilateurs récents supportent deux façons d'indiquer des commentaires en C : @@ -50,7 +50,7 @@ Même si ce programme est très simple, il illustre quelques concepts de base en - un commentaire sur une ligne est précédé des caractères `//` - un commentaire qui comprend plusieurs lignes débute par `/*` et se termine par `*/` -Ensuite, un programme écrit en langage C comprend principalement des expressions en langage C mais également des expressions qui doivent être traduites par le :term:`préprocesseur`. Lors de la compilation d'un fichier en langage C, le compilateur commence toujours par exécuter le préprocesseur. Celui-ci implémente différentes formes de macros qui permettent notamment d'inclure des fichiers (directives ``#include``), de compiler de façon conditionnelle certaines lignes ou de définir des constantes. Nous verrons différentes utilisations du préprocesseur C dans le cadre de ce cours. A ce stade, les trois principales fonctions du préprocesseur sont : +Ensuite, un programme écrit en langage C comprend principalement des expressions en langage C mais également des expressions qui doivent être traduites par le :term:`préprocesseur`. Lors de la compilation d'un fichier en langage C, le compilateur commence toujours par exécuter le préprocesseur. Celui-ci implémente différentes formes de macros qui permettent notamment d'inclure des fichiers (directives ``#include``), de compiler de façon conditionnelle certaines lignes ou de définir des constantes. Nous verrons différentes utilisations du préprocesseur C dans le cadre de ce cours. À ce stade, les trois principales fonctions du préprocesseur sont : - définir des substitutions via la macro ``#define``. Cette macro est très fréquemment utilisée pour définir des constantes ou des substitutions qui sont valables dans l'ensemble du programme. @@ -90,7 +90,7 @@ Le langage Java a été largement inspiré du langage C et de nombreuses constru - ``char`` : utilisé lors de la déclaration d'une variable permettant de stocker un caractère - ``double`` et ``float`` pour les variables permettant de stocker un nombre représenté en virgule flottante. -Notez que dans les premières versions du langage C, contrairement à Java, il n'y avait pas de type spécifique permettant de représenter un booléen. Dans de nombreux programmes écrits en C, les booléens sont représentés par des entiers et les valeurs booléenne sont définies [#fbool]_ comme suit. +Notez que dans les premières versions du langage C, contrairement à Java, il n'y avait pas de type spécifique permettant de représenter un booléen. Dans de nombreux programmes écrits en C, les booléens sont représentés par des entiers et les valeurs booléennes sont définies [#fbool]_ comme suit. .. code-block:: c @@ -147,12 +147,12 @@ Par convention, en C le premier argument (se trouvant à l'indice ``0`` du table Outre le traitement des arguments, une autre différence importante entre Java et C est la valeur de retour de la fonction ``main``. En C, la fonction ``main`` retourne un entier. Cette valeur de retour est passée par le système d'exploitation au programme (typiquemment un :term:`shell` ou interpréteur de commandes) qui a demandé l'exécution du programme. Grâce à cette valeur de retour il est possible à un programme d'indiquer s'il s'est exécuté correctement ou non. Par convention, un programme qui s'exécute sous Unix doit retourner ``EXIT_SUCCESS`` lorsqu'il se termine correctement et ``EXIT_FAILURE`` en cas d'échec. La plupart des programmes fournis avec un Unix standard respectent cette convention. Dans certains cas, d'autres valeurs de retour non nulles sont utilisées pour fournir plus d'informations sur la raison de l'échec. En pratique, l'échec d'un programme peut être dû aux arguments incorrects fournis par l'utilisateur ou à des fichiers qui sont inaccessibles. -A titre d'illustration, le programme :download:`src/failure.c` est le programme le plus simple qui échoue lors de son exécution. +À titre d'illustration, le programme :download:`src/failure.c` est le programme le plus simple qui échoue lors de son exécution. .. literalinclude:: src/failure.c :language: c -Enfin, le dernier point à mentionner concernant notre programme :download:`src/hello.c` est la fonction ``printf``. Cette fonction de la librairie standard se retrouve dans la plupart des programmes écrits en C. Elle permet l'affichage de différentes formes de textes sur la sortie standard. Comme toutes les fonctions de la librairie standard, elle est documentée dans sa page de manuel `printf(3)`_. `printf(3)`_ prend un nombre variable d'arguments. Le premier argument est une chaîne de caractères qui spécifie le format de la chaîne de caractères à afficher. Une présentation détaillée de `printf(3)`_ prendrait de nombreuses pages. A titre d'exemple, voici un petit programme utilisant `printf(3)`_ +Enfin, le dernier point à mentionner concernant notre programme :download:`src/hello.c` est la fonction ``printf``. Cette fonction de la librairie standard se retrouve dans la plupart des programmes écrits en C. Elle permet l'affichage de différentes formes de textes sur la sortie standard. Comme toutes les fonctions de la librairie standard, elle est documentée dans sa page de manuel `printf(3)`_. `printf(3)`_ prend un nombre variable d'arguments. Le premier argument est une chaîne de caractères qui spécifie le format de la chaîne de caractères à afficher. Une présentation détaillée de `printf(3)`_ prendrait de nombreuses pages. À titre d'exemple, voici un petit programme utilisant `printf(3)`_ .. literalinclude:: src/printf.c :language: c @@ -202,6 +202,8 @@ Toutes les tables de caractères placent les chiffres ``0`` à ``9`` à des posi Dans la version online de ces notes, toutes les références vers un programme Unix, un appel système ou une fonction de la librairie pointent vers la page de manuel Linux correspondante. +Il existe de nombreux livres consacrés au langage C. La référence la plus classique est [KernighanRitchie1998]_, mais certains éléments comments à dater. Un tutorial intéressant a été publié par Brian Kernighan [Kernighan]_. [King2008]_ propose une présentation plus moderne du langage C. + .. rubric:: Footnotes @@ -211,6 +213,6 @@ Toutes les tables de caractères placent les chiffres ``0`` à ``9`` à des posi .. [#fmain] Il est également possible d'utiliser dans un programme C une fonction ``main`` qui ne prend pas d'argument. Sa signature sera alors ``int main (void)``. -.. [#fenvp] En pratique, le système d'exploitation passe également les variables d'environnement à la fonction ``main``. Nous verrons plus tard comment ces variables d'environnement sont passées du système au programme et comment celui-ci peut y accéder. Sachez cependant que sous certaines variantes de Unix, et notamment Darwin/MacOS ainsi que sous certaines versions de Windows, le prototype de la fonction ``main`` inclut explicitement ces variables d'environnement (``int main(int argc, char *argv[], char *envp[])`` +.. [#fenvp] En pratique, le système d'exploitation passe également les variables d'environnement à la fonction ``main``. Nous verrons plus tard comment ces variables d'environnement sont passées du système au programme et comment celui-ci peut y accéder. Sachez cependant que sous certaines variantes de Unix, et notamment Darwin/MacOS ainsi que sous certaines versions de Windows, le prototype de la fonction ``main`` inclut explicitement ces variables d'environnement (``int main(int argc, char *argv[], char *envp[])``) diff --git a/Theorie/C/linker.rst b/Theorie/C/linker.rst index e3d030eaa8484474ce5ac8a72a046bddcd1f9e9a..05f989c095070ac982eb40a1f350a10550488f3c 100644 --- a/Theorie/C/linker.rst +++ b/Theorie/C/linker.rst @@ -80,7 +80,7 @@ Un autre exemple d'utilisation de pointeurs vers des pointeurs est la fonction ` long strtol(const char *restrict str, char **restrict endptr, int base); -L'utilisation principale de `strtol(3)`_ est de convertir une chaîne de caractères en un nombre. La fonction `atoi(3)`_ fait de même et l'expression ``atoi("1252")`` retourne l'entier ``1252``. Malheureusement, la fonction `atoi(3)`_ ne traite pas correctement les chaînes de caractères qui ne contiennent pas un nombre. Elle ne retourne pas de code d'erreur et ne permet pas savoir quelle partie de la chaîne de caractères passée en argument était en erreur. +L'utilisation principale de `strtol(3)`_ est de convertir une chaîne de caractères en un nombre. La fonction `atoi(3)`_ fait de même et l'expression ``atoi("1252")`` retourne l'entier ``1252``. Malheureusement, la fonction `atoi(3)`_ ne traite pas correctement les chaînes de caractères qui ne contiennent pas un nombre. Elle ne retourne pas de code d'erreur et ne permet pas de savoir quelle partie de la chaîne de caractères passée en argument était en erreur. `strtol(3)`_ est un exemple de fonction qui doit retourner deux types d'informations. Tout d'abord, `strtol(3)`_ retourne un résultat (dans ce cas un nombre). Si la chaîne de caractères à convertir est erronée, `strtol(3)`_ convertit le début de la chaîne et retourne un pointeur indiquant le premier caractère en erreur. Pour bien comprendre le fonctionnement de `strtol(3)`_, considérons l'exemple ci-dessous. @@ -95,7 +95,7 @@ Lors de son exécution, ce programme affiche la sortie suivante. :encoding: utf-8 :language: console -L'appel à `strtol(3)`_ prend trois arguments. Tout d'abord un pointeur vers la chaîne de caractères à convertir. Ensuite l'adresse d'un pointeur vers une chaîne de caractères. Enfin la base de conversion. La première chaîne de caractères est correcte. Elle est convertie directement. La seconde par contre contient un caractère erroné. Lors de son exécution, `strtol(3)`_ va détecter la présence du caractère ``m`` et placera un pointeur vers ce caractère dans ``*p``. Pour que la fonction `strtol(3)`_ puisse retourner un pointeur de cette façon, il est nécessaire que son second argument soit de type ``char **``. Si le second argument était de type ``char *``, la fonction `strtol(3)`_ recevrait l'adresse d'une zone mémoire contenant un caractère. Comme le langage C utilise la passage par valeur, `strtol(3)`_ pourrait modifier la caractère pointé par ce pointeur mais pas son adresse. En utilisant un second argument de type ``char **``, `strtol(3)`_ a la possibilité de modifier la valeur pointée par ce pointeur. +L'appel à `strtol(3)`_ prend trois arguments. Tout d'abord un pointeur vers la chaîne de caractères à convertir. Ensuite l'adresse d'un pointeur vers une chaîne de caractères. Enfin la base de conversion. La première chaîne de caractères est correcte. Elle est convertie directement. La seconde par contre contient un caractère erroné. Lors de son exécution, `strtol(3)`_ va détecter la présence du caractère ``m`` et placera un pointeur vers ce caractère dans ``*p``. Pour que la fonction `strtol(3)`_ puisse retourner un pointeur de cette façon, il est nécessaire que son second argument soit de type ``char **``. Si le second argument était de type ``char *``, la fonction `strtol(3)`_ recevrait l'adresse d'une zone mémoire contenant un caractère. Comme le langage C utilise le passage par valeur, `strtol(3)`_ pourrait modifier la caractère pointé par ce pointeur mais pas son adresse. En utilisant un second argument de type ``char **``, `strtol(3)`_ a la possibilité de modifier la valeur pointée par ce pointeur. Une implémentation partielle de `strtol(3)`_ pourrait être la suivante. @@ -246,6 +246,8 @@ A titre d'exemple, le programme ci-dessous utilise `strerror(3)`_ pour afficher .. rubric:: Footnotes -.. [#frestrict] La qualificateur ``restrict`` est également parfois utilisé pour indiquer des contraintes sur les pointeurs passés en argument à une fonction [Walls2006]. + +.. [#frestrict] La qualificateur ``restrict`` est également parfois utilisé pour indiquer des contraintes sur les pointeurs passés en argument à une fonction [Walls2006]_. + diff --git a/Theorie/C/src/filterdigit.c b/Theorie/C/src/filterdigit.c index dd9563c86d76957fb234d0f2e10071615d2b353e..f242bef2aacceec6c8fb990f213498cc434af4e3 100644 --- a/Theorie/C/src/filterdigit.c +++ b/Theorie/C/src/filterdigit.c @@ -10,6 +10,8 @@ #include <stdlib.h> // retourne vrai si c est un chiffre, faux sinon +// exemple simplifié, voir isdigit dans la librarire standard +// pour une solution complète int digit(char c) { return ((c >= '0') && (c <= '9')); diff --git a/Theorie/C/src/ptr_arith.c b/Theorie/C/src/ptr_arith.c index c25de6b13cf875df66a0d6182b1c53a43fc071be..a4fe502d3f8e3240fbda0ae56bc75c33d923fa66 100644 --- a/Theorie/C/src/ptr_arith.c +++ b/Theorie/C/src/ptr_arith.c @@ -18,7 +18,7 @@ tab[2] = 0x090A0B0C; int i; for (i = 0; i < SIZE; i++) { - printf("%X est a l'adresse %p\n", tab[i], &(tab[i])); + printf("%X est à l'adresse %p\n", tab[i], &(tab[i])); } ///DDD @@ -27,7 +27,7 @@ for (i = 0; i < SIZE; i++) { unsigned int* ptr = tab; for (i = 0; i < SIZE; i++) { - printf("%X est a l'adresse %p\n", *ptr, ptr); + printf("%X est à l'adresse %p\n", *ptr, ptr); ptr++; } @@ -38,7 +38,7 @@ for (i = 0; i < SIZE; i++) { unsigned char* ptr_char = (unsigned char *) tab; printf("ptr_char contient %p\n", ptr_char); for (i = 0; i < SIZE + 1; i++) { - printf("%X est a l'adresse %p\n", *ptr_char, ptr_char); + printf("%X est à l'adresse %p\n", *ptr_char, ptr_char); ptr_char++; } diff --git a/Theorie/Fichiers/fichiers-signaux.rst b/Theorie/Fichiers/fichiers-signaux.rst index 7935bc002fa147faf14558048a3d0d1ebcbedbf6..15ceeab6ce67d9e8eb23df11f8cc128e3a242e74 100644 --- a/Theorie/Fichiers/fichiers-signaux.rst +++ b/Theorie/Fichiers/fichiers-signaux.rst @@ -46,7 +46,7 @@ Avant d'analyser en détails le fonctionnement des appels systèmes `signal(2)`_ - ``SIGBUS``. Ce signal correspond à une erreur au niveau matériel. Par défaut, la réception de ce signal provoque la terminaison du processus. - ``SIGSEGV``. Ce signal correspond à une erreur dans l'accès à la mémoire, typiquement une tentative d'accès en dehors de la zone mémoire allouée au processus. Par défaut, la réception de ce signal provoque la terminaison du processus. - ``SIGFPE``. Ce signal correspond à une erreur au niveau de l'utilisation des fonctions mathématiques, notamment en virgule flottante mais pas seulement. Par défaut, la réception de ce signal provoque la terminaison du processus. - - ``SIGTERM``. Ce signal est le signal utilisé par défaut par la commande `kill(1)`_ pour demander la fin d'un processus. Par défaut, le réception de ce signal provoque la terminaison du processus. + - ``SIGTERM``. Ce signal est le signal utilisé par défaut par la commande `kill(1)`_ pour demander la fin d'un processus. Par défaut, la réception de ce signal provoque la terminaison du processus. - ``SIGKILL``. Ce signal permet de forcer la fin d'un processus. Alors qu'un processus peut définir un handler pour le signal ``SIGTERM``, il n'est pas possible d'en définir un pour ``SIGKILL``. Ce signal est le seul qui ne peut être traité et ignoré par un processus. - ``SIGUSR1`` et ``SIGUSR2`` sont deux signaux qui peuvent être utilisés par des processus sans conditions particulières. Par défaut, la réception d'un tel signal provoque la terminaison du processus. - ``SIGCHLD``. Ce signal indique qu'un processus fils s'est arrêté ou a fini son exécution. Par défaut ce signal est ignoré. @@ -396,7 +396,7 @@ Il est important de noter que les sémaphores nommés sont une ressource génér Partage de fichiers =================== -Les fichiers sont l'un des principaux moyens de communication entre processus. L'avantage majeur des fichiers est leur persistence. Les données sauvegardées dans un fichier persistent sur le système de fichiers après la fin du processus qui les a écrites. L'inconvénient majeur de l'utilisation de fichiers par rapport à d'autres techniques de communication entre processus est la relative lenteur des dispositifs de stockage en comparaison avec les accès à la mémoire. Face à cette lenteur des dispositifs de stockage, la majorité des systèmes d'exploitation utilisent des buffers qui servent de tampons entre les processus et les dispositifs de stockage. Lorsqu'un processus écrit une donnée sur un dispositif de stockage, celle-ci est d'abord écrite dans un buffer géré par le système d'exploitation et le processus peut poursuivre son exécution sans devoir attendre l'exécution compléte de l'écriture sur le dispositif de stockage. La taille de ces buffers varie généralement dynamiquement en fonction de la charge du système. Les données peuvent y rester entre quelques fractions de seconde et quelques dizaines de secondes. Un processus peut contrôler l'utilisation de ce buffer en utilisant l'appel système `fsync(2)`_. Celui-ci permet de forcer l'écriture sur le dispositif de stockage des données du fichier identifié par le descripteur de fichiers passé en argument. L'appel système `sync(2)`_ force quant à lui l'écriture de toutes les données actuellement stockées dans les buffers du noyau sur les dispositifs de stockage. Cet appel système est notamment utilisé par un processus système qui l'exécute toutes les trente secondes afin d'éviter que des données ne restent trop longtemps dans les buffers du noyau. +Les fichiers sont l'un des principaux moyens de communication entre processus. L'avantage majeur des fichiers est leur persistence. Les données sauvegardées dans un fichier persistent sur le système de fichiers après la fin du processus qui les a écrites. L'inconvénient majeur de l'utilisation de fichiers par rapport à d'autres techniques de communication entre processus est la relative lenteur des dispositifs de stockage en comparaison avec les accès à la mémoire. Face à cette lenteur des dispositifs de stockage, la majorité des systèmes d'exploitation utilisent des buffers qui servent de tampons entre les processus et les dispositifs de stockage. Lorsqu'un processus écrit une donnée sur un dispositif de stockage, celle-ci est d'abord écrite dans un buffer géré par le système d'exploitation et le processus peut poursuivre son exécution sans devoir attendre l'exécution complète de l'écriture sur le dispositif de stockage. La taille de ces buffers varie généralement dynamiquement en fonction de la charge du système. Les données peuvent y rester entre quelques fractions de seconde et quelques dizaines de secondes. Un processus peut contrôler l'utilisation de ce buffer en utilisant l'appel système `fsync(2)`_. Celui-ci permet de forcer l'écriture sur le dispositif de stockage des données du fichier identifié par le descripteur de fichiers passé en argument. L'appel système `sync(2)`_ force quant à lui l'écriture de toutes les données actuellement stockées dans les buffers du noyau sur les dispositifs de stockage. Cet appel système est notamment utilisé par un processus système qui l'exécute toutes les trente secondes afin d'éviter que des données ne restent trop longtemps dans les buffers du noyau. .. index:: open file object @@ -422,7 +422,7 @@ Lors de son exécution, deux open file objects sont créés dans le noyau. Le pr Les open file objects sont également utilisés lorsque plusieurs processus ouvrent le même fichier. Considérons l'exécutions simultanée des deux commandes suivantes : -.. code-block:: c +.. code-block:: console $ prog1 file & $ prog2 file & @@ -444,7 +444,7 @@ Sous Unix et Linux, il est important d'analyser également ce qu'il se passe lor Cette utilisation d'un même open-file object par le processus père et le processus fils est une particularité importante de Unix. Elle permet aux deux processus d'écrire des données séquentiellement dans un fichier qui avait été initialement ouvert par le processus père, mais pose régulièrement des problèmes lors de la manipulation de fichiers. -Lorsqu'un fichier est utilisé par plusieurs processus simultanément, il est nécessaire de coordonner les activités de ces processus pour éviter que le fichier ne devienne corrompu. Outres les appels systèmes classiques `open(2)`_, `read(2)`_, `write(2)`_ et `close(2)`_, Unix offre plusieurs appels systèmes qui sont utiles lorsque plusieurs processus accèdent au même fichier. +Lorsqu'un fichier est utilisé par plusieurs processus simultanément, il est nécessaire de coordonner les activités de ces processus pour éviter que le fichier ne devienne corrompu. Outre les appels systèmes classiques `open(2)`_, `read(2)`_, `write(2)`_ et `close(2)`_, Unix offre plusieurs appels systèmes qui sont utiles lorsque plusieurs processus accèdent au même fichier. Considérons d'abord un processus père et un processus fils qui doivent lire des données à des endroits particuliers dans un fichier. Pour cela, il est naturel d'utiliser l'appel système `lseek(2)`_ pour déplacer l'offset pointer et d'ensuite réaliser la lecture avec `read(2)`_. Malheureusement lorsqu'un père et un ou plusieurs fils [#fthreads]_ utilisent ces appels systèmes, il est possible qu'un appel à `lseek(2)`_ fait par le fils soit immédiatement suivi d'un appel à `lseek(2)`_ fait par le père avant que le fils ne puisse exécuter l'appel système `read(2)`_. Dans ce cas, le processus fils ne lira pas les données qu'il souhaitait lire dans le fichier. Les appels systèmes `pread(2)`_ et `pwrite(2)`_ permettent d'éviter ce problème. Ils complètent les appels systèmes `read(2)`_ et `write(2)`_ en prenant comme argument l'offset auquel la lecture ou l'écriture demandée doit être effectuée. `pread(2)`_ et `pwrite(2)`_ garantissent que les opérations d'écriture et de lecture qui sont effectuées avec ces appels systèmes seront atomiques. @@ -548,7 +548,7 @@ Sous Linux, le système de fichiers virtuel ``/proc`` fournit une interface perm 17: FLOCK ADVISORY WRITE 2967 08:01:797391 0 EOF 18: FLOCK ADVISORY WRITE 1278 08:01:652815 0 EOF -Dans ce fichier, la première colonne indique le type de lock (``POSIX`` pour un lock placé avec `fcntl(2)`_ ou `lockf(3)`_ et ``FLOCK`` pour un lock placé avec `flock(2)`_). La deuxième indique si le lock est un :term:`advisory lock` ou un :term:`mandatory lock`. La troisième spécifie si le lock protège l'écriture et/ou la lecture. La cinquième colonne est l'identifiant du processus qui possède le lock. La sixième précise le dispositif de stockage et le fichier concerné par ce lock (le dernier nombre est l'inode du fichier). Enfin, les deux dernières colonnes spécifient la section qui est couverte par le lock avec ``EOF`` qui indique la fin du fichier. +Dans ce fichier, la première colonne indique le type de lock (``POSIX`` pour un lock placé avec `fcntl(2)`_ ou `lockf(3)`_ et ``FLOCK`` pour un lock placé avec `flock(2)`_). La deuxième indique si le lock est un :term:`advisory lock` ou un :term:`mandatory lock`. La troisième spécifie si le lock protège l'écriture et/ou la lecture. La quatrième colonne est l'identifiant du processus qui possède le lock. La cinquième précise le dispositif de stockage et le fichier concerné par ce lock (le dernier nombre est l'inode du fichier). Enfin, les deux dernières colonnes spécifient la section qui est couverte par le lock avec ``EOF`` qui indique la fin du fichier. .. rubric:: Footnotes diff --git a/Theorie/Fichiers/fichiers.rst b/Theorie/Fichiers/fichiers.rst index f383f34a92b4bd76d0c068ccb3eb5db97b550173..c12b7d85663d5c3d42d63cd23975c1bcabb9ee70 100644 --- a/Theorie/Fichiers/fichiers.rst +++ b/Theorie/Fichiers/fichiers.rst @@ -462,7 +462,7 @@ Cet appel système prend trois arguments. Le premier est le :term:`descripteur d .. code-block:: c - char template[]="/tmp/sinf1252PROCXXXXXX" + char template[]="/tmp/sinf1252PROCXXXXXX"; int fd=mkstemp(template); if(fd==-1) @@ -472,7 +472,7 @@ Cet appel système prend trois arguments. Le premier est le :term:`descripteur d // le fichier est effacé, mais reste accessible // via son descripteur jusqu'à close(fd) - / Accès au fichier avec read et write + // Accès au fichier avec read et write if(close(fd)==-1) exit_on_error("close"); diff --git a/Theorie/Makefile b/Theorie/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9ba663ec0638a6ca8fb361a49d13c7c75fe3dfb1 --- /dev/null +++ b/Theorie/Makefile @@ -0,0 +1,161 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = a4 +BUILDDIR = ../web/notes/Theorie + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext qcm projets sinf1252 + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SINF1252.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SINF1252.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/SINF1252" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SINF1252" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +qcm: + @for dir in Exercices/QCM/S*; do make -C $${dir}; done + +projets: + @for dir in Projets/P*; do [ -e $${dir}/Makefile ] && make -C $${dir}; true; done + +sinf1252: qcm projets html latexpdf epub diff --git a/Theorie/MemoireVirtuelle/vmem.rst b/Theorie/MemoireVirtuelle/vmem.rst index 8673353e08685f500ed4ad3d0f905ce147cb9e24..314e5f10ff27f8106b63d23ddd1ed0bfd2efe24b 100644 --- a/Theorie/MemoireVirtuelle/vmem.rst +++ b/Theorie/MemoireVirtuelle/vmem.rst @@ -259,7 +259,7 @@ Considérons une opération de lecture faite par le CPU. Pour réaliser cette op - les bits de permission permettent l'accès à la page. On parle dans ce cas de :term:`page fault`, c'est-à -dire qu'une page nécessaire à l'exécution du processus n'est pas disponible en mémoire RAM. Vu les temps d'accès et la complexité d'accéder à une page sur un disque dur (via une partition, un fichier de swap ou un fichier normal), le :term:`MMU` ne peut pas accéder directement à la donnée sur le disque dur. Le :term:`MMU` va donc générer une interruption qui va forcer l'exécution d'une routine de traitement d'interruption par le noyau. Cette routine va identifier la page manquante et préparer son transfert du disque dur vers la mémoire. Ce transfert peut durer plusieurs dizaines de millisecondes, ce qui est un temps très long par rapport à l'exécution d'instructions par le processeur. Tant que cette page n'est pas disponible en mémoire RAM, le processus ne peut continuer son exécution. Il passe dans l'état bloqué et le noyau effectue un changement de contexte pour exécuter un autre processus. Lorsque la page manquante aura été rapatriée depuis le disque dur en mémoire RAM, le noyau pourra relancer le processus qu'il avait bloqué afin de retenter l'accès mémoire qui vient d'échouer. -Durant son exécution, un système doit pouvoir gérer des pages qui se trouvent en mémoire RAM et des pages qui sont stockées sur le disque dur. Lorsque la mémoire RAM en entièrement remplies de pages, il peut être nécessaire d'y libérer de l'espace mémoire et déplaçant des pages vers un des dispositifs de stockage. C'est le rôle des algorithmes de remplacement de pages. +Durant son exécution, un système doit pouvoir gérer des pages qui se trouvent en mémoire RAM et des pages qui sont stockées sur le disque dur. Lorsque la mémoire RAM est entièrement remplies de pages, il peut être nécessaire d'y libérer de l'espace mémoire en déplaçant des pages vers un des dispositifs de stockage. C'est le rôle des algorithmes de remplacement de pages. .. _remplacement: @@ -268,11 +268,11 @@ Stratégies de remplacements de pages C'est le système d'exploitation qui prend en charge les transferts de pages entre les dispositifs de stockage et la mémoire. Tant que la mémoire RAM n'est pas remplie, ces transferts sont simples, il suffit de ramener une ou plusieurs pages du dispositif de stockage vers la mémoire RAM. En général, le système d'exploitation cherchera à exploiter le principe de localité lors de ces transferts. Lorsqu'une page manque en mémoire RAM, le noyau programmera le chargement de cette page, mais aussi d'autres pages du même processus ayant des adresses proches. -Lorsque la mémoire RAM est remplie et qu'il faut ramener une page depuis un dispositif de stockage, le problème est plus délicat. Pour pouvoir charger cette nouvelle page en mémoire RAM, le système d'exploitation doit libérer de la mémoire. Pour cela, il doit implémenter une :term:`stratégie de remplacement des pages` en mémoire. Cette stratégie définit quelle page doit être préférentiellement retirée de la mémoire RAM et placée sur le dispositif de stockage. Différentes stratégies sont possibles. Elles résultent en général d'un compromis entre la quantité d'information de contrôle qui est stockée dans la table des pages et les performances de la stratégie de remplacement des pages. +Lorsque la mémoire RAM est remplie et qu'il faut ramener une page depuis un dispositif de stockage, le problème est plus délicat. Pour pouvoir charger cette nouvelle page en mémoire RAM, le système d'exploitation doit libérer de la mémoire. Pour cela, il doit implémenter une :term:`stratégie de remplacement de pages` en mémoire. Cette stratégie définit quelle page doit être préférentiellement retirée de la mémoire RAM et placée sur le dispositif de stockage. Différentes stratégies sont possibles. Elles résultent en général d'un compromis entre la quantité d'information de contrôle qui est stockée dans la table des pages et les performances de la stratégie de remplacement des pages. Une première stratégie de remplacement de pages pourrait être de sauvegarder les identifiants des pages dans une :term:`file FIFO`. Chaque fois qu'une page est créée par le noyau, son identifiant est placé à la fin de la :term:`file FIFO`. Lorsque la mémoire est pleine et qu'une page doit être retirée de la mémoire RAM, le noyau pourrait choisir la page dont l'identifiant se trouve en tête de la :term:`file FIFO`. Cette stratégie a l'avantage d'être simple à implémenter, mais remettre sur disque la page la plus anciennement créée n'est pas toujours la solution la plus efficace du point de vue des performances. En effet, cette page peut très bien être une des pages les plus utilisées par le processeur. Si elle est remise sur le disque, elle risque de devoir être récupérée peu de temps après. -Au niveau des performances, la meilleure stratégie de remplacement de pages serait de sauvegarder sur le disque dur les pages qui seront utilisées par le processeur d'ici le plus de temps possible. Malheureusement, cette stratégie nécessite de prévoir le futur, une fonctionnalité qui n'existe pas dans les systèmes d'exploitation actuels... Une solution alternative serait de comptabiliser les accès aux différentes pages et de sauvegarder sur disque les pages qui ont été les moins utilisées. Cette solution est séduisante d'une point de vue théorique car en disposant de statistiques sur l'utilisation des pages, le système d'exploitation devrait pouvoir être capable de mieux prédire les pages qui seront nécessaires dans le futur et les conserver en mémoire RAM. Du point de vue de l'implémentation par contre, cette solution est loin d'être réaliste. En effet, pour maintenir un compteur du nombre d'accès à une page, il faut consommer de la mémoire supplémentaire dans chaque entrée de la table des pages. Mais il faut aussi que le :term:`TLB` puisse incrémenter ce compteur lors de chaque accès à une de ces entrées. Cela augmente inutilement la complexité du :term:`TLB`. +Au niveau des performances, la meilleure stratégie de remplacement de pages serait de sauvegarder sur le disque dur les pages qui seront utilisées par le processeur d'ici le plus de temps possible. Malheureusement, cette stratégie nécessite de prévoir le futur, une fonctionnalité qui n'existe pas dans les systèmes d'exploitation actuels... Une solution alternative serait de comptabiliser les accès aux différentes pages et de sauvegarder sur disque les pages qui ont été les moins utilisées. Cette solution est séduisante du point de vue théorique car en disposant de statistiques sur l'utilisation des pages, le système d'exploitation devrait pouvoir être capable de mieux prédire les pages qui seront nécessaires dans le futur et les conserver en mémoire RAM. Du point de vue de l'implémentation par contre, cette solution est loin d'être réaliste. En effet, pour maintenir un compteur du nombre d'accès à une page, il faut consommer de la mémoire supplémentaire dans chaque entrée de la table des pages. Mais il faut aussi que le :term:`TLB` puisse incrémenter ce compteur lors de chaque accès à une de ces entrées. Cela augmente inutilement la complexité du :term:`TLB`. Stocker dans le :term:`TLB` l'instant du dernier accès à une page de façon à pouvoir déterminer quelles sont les pages auxquelles le système a accédé depuis le plus longtemps est une autre solution séduisante d'un point de vue théorique. Du point de vue de l'implémentation, c'est loin d'être facilement réalisable. Tout d'abord, pour que cet instant soit utile, il faut probablement disposer d'une résolution d'une milliseconde voire mieux. Une telle résolution consommera au moins quelques dizaines de bits dans chaque entrée de la table des pages. En outre, le :term:`TLB` devra pouvoir mettre à jour cette information lors de chaque accès. diff --git a/Theorie/Threads/coordination.rst b/Theorie/Threads/coordination.rst index 7ff092de149a4e825d22626cd82c02fb5bb3ee3d..48bd35d78bba34222b0460d5f21fb53aa8ce54d7 100644 --- a/Theorie/Threads/coordination.rst +++ b/Theorie/Threads/coordination.rst @@ -260,7 +260,7 @@ Une première solution à ce problème est d'utiliser un mutex et un sémaphore sem_init(&db, NULL, 1). -La solution utilise une variable partagée : ``readcount``. L'accès à cette variable est protégé par ``mutex``. Le sémaphore ``db`` sert à réguler l'accès des `writers` à la base de données. Le mutex est initiliasé comme d'habitude par la fonction `pthread_mutex_init(3posix)`_. Le sémaphore ``db`` est initialisé à la valeur ``1``. Le `writer` est assez simple : +La solution utilise une variable partagée : ``readcount``. L'accès à cette variable est protégé par ``mutex``. Le sémaphore ``db`` sert à réguler l'accès des `writers` à la base de données. Le mutex est initialisé comme d'habitude par la fonction `pthread_mutex_init(3posix)`_. Le sémaphore ``db`` est initialisé à la valeur ``1``. Le `writer` est assez simple : .. code-block:: c @@ -469,7 +469,7 @@ Dans un programme C séquentiel, on doit souvent combiner les variables globales Une première solution serait d'utiliser une zone mémoire qui est spécifique au thread et d'y placer par exemple une structure contenant toutes les variables auxquelles on souhaite pouvoir accéder depuis toutes les fonctions du thread. Cette zone mémoire pourrait être créée avant l'appel à `pthread_create(3)`_ et un pointeur vers cette zone pourrait être passé comme argument à la fonction qui démarre le thread. Malheureusement l'argument qui est passé à cette fonction n'est pas équivalent à une variable globale et n'est pas accessible à toutes les fonctions du thread. -Une deuxième solution serait d'avoir un tableau global qui contiendrait des pointeurs vers des zones de mémoires qui ont été allouées pour chaque thread. Chaque thread pourrait alors accéder à ce tableau sur base de son identifiant. Cette solution pourrait fonctionner si le nombre de threads est fixe et que les identifiants de threads sont des entiers croissants. Malheureusement la libraire threads POSIX ne fournit pas de tels identifiants croissants. Officiellement, la fonction `pthread_self(3)`_ retourne un identifiant unique d'un thread qui a été créé. Malheureusement cet identifiant est de type ``pthread_t`` et ne peut pas être utilisé comme index dans un tableau. Sous Linux, l'appel système non-standard `gettid(2)`_ retourne l'identifiant du thread, mais il ne peut pas non plus être utilisé comme index dans un tableau. +Une deuxième solution serait d'avoir un tableau global qui contiendrait des pointeurs vers des zones de mémoires qui ont été allouées pour chaque thread. Chaque thread pourrait alors accéder à ce tableau sur base de son identifiant. Cette solution pourrait fonctionner si le nombre de threads est fixe et que les identifiants de threads sont des entiers croissants. Malheureusement la librairie threads POSIX ne fournit pas de tels identifiants croissants. Officiellement, la fonction `pthread_self(3)`_ retourne un identifiant unique d'un thread qui a été créé. Malheureusement cet identifiant est de type ``pthread_t`` et ne peut pas être utilisé comme index dans un tableau. Sous Linux, l'appel système non-standard `gettid(2)`_ retourne l'identifiant du thread, mais il ne peut pas non plus être utilisé comme index dans un tableau. Pour résoudre ce problème, deux solutions sont possibles. La première combine une extension au langage C qui est supportée par `gcc(1)`_ avec la librairie threads POSIX. il s'agit du qualificatif ``__thread`` qui peut être utilisé avant une déclaration de variable. Lorsqu'il est utilisé dans la déclaration d'une variable globale, il indique au compilateur et à la libraire POSIX qu'une copie de cette variable doit être créée pour chaque thread. Cette variable est initialisée au démarrage du thread et est utilisable uniquement à l'intérieur de ce thread. Le programme ci-dessous illustre cette utilisation du qualificatif ``__thread``. diff --git a/Theorie/Threads/processus.rst b/Theorie/Threads/processus.rst index 9e4596da08effdb6a45081e15848ce8c62c6d595..57e8657acb3a49b93b3b79512cdfca94dfed1743 100644 --- a/Theorie/Threads/processus.rst +++ b/Theorie/Threads/processus.rst @@ -38,7 +38,7 @@ Lors de l'utilisation de telles librairies, on s'attendrait à ce que toutes les Une analyse plus détaillée de l'exécutable avec `objdump(1)`_ révèle que si l'exécutable contient bien des appels à ces fonctions, leur code n'y est pas entièrement inclus. -.. code-block:: c-objdump +.. code-block:: console $gcc -g -lm math.c -o math $objdump -S -d math diff --git a/Theorie/_static b/Theorie/_static new file mode 120000 index 0000000000000000000000000000000000000000..7a2b653646f86d98f976df94c66c017b5d24ecbe --- /dev/null +++ b/Theorie/_static @@ -0,0 +1 @@ +../_static \ No newline at end of file diff --git a/Theorie/bib.rst b/Theorie/bib.rst new file mode 100644 index 0000000000000000000000000000000000000000..67670a1ded9718f7005808ae584b7db9f3ebbb79 --- /dev/null +++ b/Theorie/bib.rst @@ -0,0 +1,102 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + +************* +Bibliographie +************* + +.. [ABS] Cooper, M., `Advanced Bash-Scripting Guide`, 2011, http://tldp.org/LDP/abs/html/ + +.. [AdelsteinLubanovic2007] Adelstein, T., Lubanovic, B., `Linux System Administration`, OReilly, 2007, http://books.google.be/books?id=-jYe2k1p5tIC + +.. [Alagarsamy2003] Alagarsamy, K., `Some myths about famous mutual exclusion algorithms`. SIGACT News 34, 3 (September 2003), 94-103. http://doi.acm.org/10.1145/945526.945527 + +.. [Amdahl1967] Amdahl, G., `Validity of the Single-Processor Approach to Achieving Large-Scale Computing Capabilities`, Proc. Am. Federation of Information Processing Societies Conf., AFIPS Press, 1967, pp. 483-485, http://dx.doi.org/10.1145/1465482.1465560 + +.. [Bashar1997] Bashar, N., `Ariane 5: Who Dunnit?`, IEEE Software 14(3): 15–16. May 1997. doi:10.1109/MS.1997.589224. + + +.. [BryantOHallaron2011] Bryant, R. and O'Hallaron, D., `Computer Systems : A programmer's perspective`, Second Edition, Pearson, 2011, http://www.amazon.com/Computer-Systems-Programmers-Perspective-2nd/dp/0136108040/ref=sr_1_1?s=books&ie=UTF8&qid=1329058781&sr=1-1 + + +.. [C99] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf + +.. [Card+1994] Card, R., Ts’o, T., Tweedie, S, `Design and implementation of the second extended filesystem`. Proceedings of the First Dutch International Symposium on Linux. ISBN 90-367-0385-9. http://web.mit.edu/tytso/www/linux/ext2intro.html + +.. [Cooper2011] Cooper, M., `Advanced Bash-Scripting Guide`, http://tldp.org/LDP/abs/html/, 2011 + +.. [Courtois+1971] Courtois, P., Heymans, F. and Parnas, D., `Concurrent control with “readers†and “writersâ€`. Commun. ACM 14, 10 (October 1971), 667-668. http://doi.acm.org/10.1145/362759.362813 + + +.. [CPP] C preprocessor manual, http://gcc.gnu.org/onlinedocs/cpp/ + +.. [Dijkstra1965b] Dijkstra, E., `Cooperating sequential processes`, 1965, http://www.cs.utexas.edu/users/EWD/transcriptions/EWD01xx/EWD123.html + +.. [Dijkstra1965] Dijkstra, E., `Solution of a problem in concurrent programming control`. Commun. ACM 8, 9 (September 1965), 569 http://doi.acm.org/10.1145/365559.365617 + +.. [Dijkstra1968] Dijkstra, E., `Go To Statement Considered Harmful`, Communications of the ACM, 11, March 1968, http://www.cs.utexas.edu/~EWD/transcriptions/EWD02xx/EWD215.html Voir aussi [Tribble2005]_ + +.. [Downey2008] Downey, A., `The Little Book of Semaphores`, Second Edition, Green Tea Press, 2008, + +.. [Drepper2007] Drepper, U., `What every programmer should know about memory`, 2007, http://www.akkadia.org/drepper/cpumemory.pdf + +.. [DrepperMolnar2005] Drepper, U., Molnar, I., `The Native POSIX Thread Library for Linux`, http://www.akkadia.org/drepper/nptl-design.pdf + +.. [Goldberg1991] Goldberg, D., `What every computer scientist should know about floating-point arithmetic`. ACM Comput. Surv. 23, 1 (March 1991), 5-48. http://doi.acm.org/10.1145/103162.103163 ou http://www.validlab.com/goldberg/paper.pdf + + +.. [Gove2011] Gove, D., `Multicore Application Programming for Windows, Linux and Oracle Solaris`, Addison-Wesley, 2011, http://books.google.be/books?id=NF-C2ZQZXekC + +.. [GNUMake] http://www.gnu.org/software/make/manual/make.html + +.. [GNUPTH] Engelschall, R., `GNU Portable Threads`, http://www.gnu.org/software/pth/ + +.. [Graham+1982] Graham, S., Kessler, P. and Mckusick, M., `Gprof: A call graph execution profiler`. SIGPLAN Not. 17, 6 (June 1982), 120-126. http://doi.acm.org/10.1145/872726.806987 + +.. [HennessyPatterson] Hennessy, J. and Patterson, D., `Computer Architecture: A Quantitative Approach`, Morgan Kauffmann, http://books.google.be/books?id=gQ-fSqbLfFoC + +.. [HP] HP, `Memory technology evolution: an overview of system memory technologies`, http://h20000.www2.hp.com/bc/docs/support/SupportManual/c00256987/c00256987.pdf + +.. [Hyde2010] Hyde, R., `The Art of Assembly Language`, 2nd edition, No Starch Press, http://webster.cs.ucr.edu/AoA/Linux/HTML/AoATOC.html + +.. [IA32] intel, `Intel® 64 and IA-32 Architectures : Software Developer’s Manual`, Combined Volumes: 1, 2A, 2B, 2C, 3A, 3B and 3C, December 2011, http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf + +.. [Kamp2011] Kamp, P., `The Most Expensive One-byte Mistake`, ACM Queue, July 2011, http://queue.acm.org/detail.cfm?id=2010365 + +.. [Kerrisk2010] Kerrisk, M., `The Linux Programming Interface`, No Starch Press, 2010, http://my.safaribooksonline.com/book/programming/linux/9781593272203 + +.. [Kernighan] Kernighan, B., `Programming in C - A Tutorial`, http://cm.bell-labs.com/cm/cs/who/dmr/ctut.pdf + +.. [KernighanRitchie1998] Kernighan, B., and Ritchie, D., `The C programming language, second edition`, Addison Wesley, 1998, http://cm.bell-labs.com/cm/cs/cbook/ + +.. [King2008] King, K., `C programming : a modern approach`, W. W. Norton & company, 2008 + +.. [Krakowiak2011] Krakowiak, S., `Le modele d'architecture de von Neumann`, http://interstices.info/le-modele-darchitecture-de-von-neumann + +.. [Leroy] Leroy, X., `The LinuxThreads library`, http://pauillac.inria.fr/~xleroy/linuxthreads/ + +.. [McKenney2005] McKenney, P., `Memory Ordering in Modern Microprocessors, Part I`, Linux Journal, August 2005, http://www.linuxjournal.com/article/8211 + +.. [Mecklenburg+2004] Mechklenburg, R., Mecklenburg, R. W., Oram, A., `Managing projects with GNU make`, O'Reilly, 2004, http://books.google.be/books?id=rL4GthWj9kcC + +.. [Mitchell+2001] Mitchell, M., Oldham, J. and Samuel, A., `Advanced Linux Programming`, New Riders Publishing, ISBN 0-7357-1043-0, June 2001, http://www.advancedlinuxprogramming.com/ + + +.. [Nemeth+2010] Nemeth, E., Hein, T., Snyder, G., Whaley, B., `Unix and Linux System Administration Handbook`, Prentice Hall, 2010, http://books.google.be/books?id=rgFIAnLjb1wC + +.. [Peterson1981] Peterson, G., `Myths about the mutual exclusion problem`, Inform. Process. Lett. 12 (3) (1981) 115-116 + +.. [Stallings2011] Stallings, W., `Operating Systems : Internals and Design Principles`, Prentice Hall, 2011, http://williamstallings.com/OperatingSystems/index.html + +.. [StevensRago2008] Stevens, R., and Rago, S., `Advanced Programming in the UNIX Environment`, Addison-Wesley, 2008, http://books.google.be/books?id=wHI8PgAACAAJ + +.. [Stokes2008] Stokes, J., `Classic.Ars: Understanding Moore's Law`, http://arstechnica.com/hardware/news/2008/09/moore.ars + +.. [Tanenbaum+2009] Tanenbaum, A., Woodhull, A., `Operating systems: design and implementation`, Prentice Hall, 2009 + + +.. [Tribble2005] Tribble, D., `Go To Statement Considered Harmful: A Retrospective`, 2005, http://david.tribble.com/text/goto.html + +.. [Walls2006] Walls, D., `How to Use the restrict Qualifier in C`. Sun Microsystems, 2006, http://developers.sun.com/solaris/articles/cc_restrict.html + diff --git a/Theorie/conf.py b/Theorie/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..5d0e50b454ba0ddd559bf895ac63a1cf3e308318 --- /dev/null +++ b/Theorie/conf.py @@ -0,0 +1,314 @@ +# -*- coding: utf-8 -*- +# +# SINF1252 documentation build configuration file, created by +# sphinx-quickstart on Tue Jan 3 16:17:09 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.mathjax', 'sphinx.ext.intersphinx' ] + +# ucomment +#sys.path.append(os.path.abspath(os.getcwd())) +#extensions.append('ucomment-extension') +#html_translator_class = 'ucomment-extension.ucomment_html_translator' + +# Point to your Django application, which contains all +# the other settings required. +#ucomment = {} +#ucomment['django_application_path'] = '/home/cpaasch/sinf1252/ucommentsite/ucommentapp' + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' +#source_encoding = 'latin1' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'SINF1252 : Systèmes informatiques' +copyright = u'2013, O. Bonaventure, G. Detal, C. Paasch' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2014' +# The full version, including alpha/beta/rc tags. +release = '2014' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = 'fr' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build/**', '.#*', '**/.#**', 'Exercices/QCM/**', "**.BASE.**", "**.REMOTE.**", "**.LOCAL.**", "**.BACKUP.**" ] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +rst_epilog = """ +.. include:: /links.rst +.. include:: /man_links.rst +.. include:: /incl_links.rst +""" + +# Intersphinx +intersphinx_mapping = {'theorie': ('https://sites.uclouvain.be/SystInfo/notes/Theorie/html/', None), 'outils': ('https://sites.uclouvain.be/SystInfo/notes/Outils/html/', None), 'exercices': ('https://sites.uclouvain.be/SystInfo/notes/Exercices/html/', None)} + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = u'Systèmes informatiques' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'SINF1252doc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +'papersize': 'a4paper', + +# The font size ('10pt', '11pt' or '12pt'). +'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'SINF1252.tex', u'SINF1252 : Systèmes informatiques', + u'O. Bonaventure, G. Detal, C. Paasch', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'sinf1252', u'SINF1252', + [u'O. Bonaventure, G. Detal, C. Paasch'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'SINF1252', u'SINF1252 : Systèmes informatiques', + u'O. Bonaventure, G. Detal, C. Paasch', 'SINF1252', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'SINF1252 : Systèmes informatiques' +epub_author = u'O. Bonaventure, G. Detal, C. Paasch' +epub_publisher = u'O. Bonaventure, G. Detal, C. Paasch' +epub_copyright = u'2013, O. Bonaventure, G. Detal, C. Paasch' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +#try: +# open('.staff','r') +# tags.add('staff') +# print "Build as staff member" +#except: +# print "Build as student" + +mathjax_path="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML" diff --git a/Theorie/glossaire.rst b/Theorie/glossaire.rst new file mode 100644 index 0000000000000000000000000000000000000000..89585efd5a3976299839bd5b7b42d354ee422c10 --- /dev/null +++ b/Theorie/glossaire.rst @@ -0,0 +1,595 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + + +********* +Glossaire +********* + +.. glossary:: + :sorted: + + CPU + Central Processing Unit + + C + Langage de programmation permettant d'interagir facilement avec le matériel. + + RISC + Reduced Instruction Set Computer + + CISC + Complex Instruction Set Computer + + x86 + Famille de microprocesseurs développée par intel_. Le 8086 est le premier processeur de cette famille. Ses successeurs (286, 386, Pentium, Centrino, Xeon, ...) sont restés compatibles avec lui tout en introduisant chacun de nouvelles instructions et de nouvelles fonctionnalités. Aujourd'hui, plusieurs fabricants développent des processeurs qui supportent le même langage machine que les processeurs de cette famille. + + Unix + Système d'exploitation développé initialement par AT&T Bell Labs. + + gcc + Compilateur pour la langage C développé par un groupe de volontaires qui est diffusé depuis http://gcc.gnu.org gcc est utilisé dans plusieurs systèmes d'exploitation de type Unix, comme MacOS, Linux ou FreeBSD. Il existe d'autres compilateurs C. Une liste non-exhaustive est maintenue sur http://en.wikipedia.org/wiki/List_of_compilers#C_compilers + + llvm + Ensemble de compilateurs pour différents langages de programmation et différents processeurs développé par un groupe de volontaire. llvm est distrubé depuis http://llvm.org/ + + cpp + préprocesseur + Le préprocesseur C est un programme de manipulation de texte sur base de macros qui est utilisé avec le compilateur. Le préprocesseur de :term:`gcc` est http://gcc.gnu.org/onlinedocs/cpp/ + + microprocesseur + processeur + à compléter + + CPU + Central Processing Unit. Voir :term:`microprocesseur` + + stdin + Entrée standard sur un système Unix (par défaut le clavier) + + stdout + Sortie standard sur un système Unix (par défaut l'écran) + + stderr + Sortie d'erreur standard sur un système Unix (par défaut l'écran) + + X11 + à compléter + + Gnome + à compléter + + CDE + à compléter + + shell + Interpréteur de commandes sur un système Unix. `bash(1)`_ est l'interpréteur de commandes le plus utilisé de nos jours. + + bit + Plus petite unité d'information. Par convention, un bit peut prendre les valeurs ``0`` et ``1``. + + nibble + Un bloc de quatre bits consécutifs. + + byte + octet + Un bloc de huit bits consécutifs. + + BSD Unix + Variante de Unix développée à l'Université de Californie à Berkeley. + + FreeBSD + Variante de BSD Unix disponible depuis http://www.freebsd.org + + OpenBSD + Variante de BSD Unix disponible depuis http://www.openbsd.org + + MacOS + Système d'exploitation développé par Apple Inc. comprenant de nombreux composantes provenant de :term:`FreeBSD` + + Minix + Famille de noyaux de systèmes d'exploitation inspiré de :term:`Unix` développée notamment par :term:`Andrew Tanenbaum`. Voir http://www.minix3.org pour la dernière version de Minix. + + Linux + Noyau de système d'exploitation compatible Unix développé initialement par Linus Torvalds. + + Solaris + Système d'exploitation compatible Unix développé par Sun Microsystems et repris par Oracle. La version open-source, OpenSolaris, est disponible depuis http://www.opensolaris.org + + Application Programming Interface + API + Un API est généralement un ensemble de fonctions et de structures de données qui constitue l'interface entre deux composants logiciels qui doivent collaborer. Par exemple, l'API du noyau d'un système Unix est composée de ses appels systèmes. Ceux-ci sont décrits dans la section 2 des pages de manuel (voir `intro(2)`_). + + GNU is not Unix + GNU + GNU est un projet open-source de la Free Software Foundation qui a permis le développement d'un grand nombre d'utilitaires utilisés par les systèmes d'exploitation de la famille Unix actuellement. + + GNU/Linux + Nom générique donné à un système d'exploitation utilisant les utilitaires :term:`GNU` notamment et le noyau :term:`Linux` . + + Andrew Tanenbaum + Andrew Tanenbaum est professeur à la VU d'Amsterdam. + + Linus Torvalds + Linus Torvalds est le créateur et le mainteneur principal du noyau :term:`Linux`. + + Aqua + Aqua est une interface graphique spécifique à :term:`MacOS`. + + pipe + Mécanisme de redirection des entrées-sorties permettant de relier la sortie standard d'un programme à l'entrée standard d'un autre pour créer des pipelines de traitement. + + assembleur + Programme permettant de convertir un programme écrit en langage d'assemblage dans le langage machine correspondant à un processeur donné. + + warning + Message d'avertissement émis par un compilateur C. Un :term:`warning` n'empêche pas la compilation et la génération du code objet. Cependant, la plupart des warnings indiquent un problème dans le programme compilé et il est nettement préférable de les supprimer du code. + + bit de poids fort + Par convention, le bit le plus à gauche d'une séquence de n bits. + + bit de poids faible + Par convention, bit le plus à droite d'une séquence de n bits. + + simple précision + Représentation de nombre réels en virgule flottante (type ``float`` en C). La norme `IEEE754 <http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=4610933>`_ définit le format de ces nombres sur 32 bits. + + double précision + Représentation de nombre réels en virgule flottante (type ``double`` en C). La norme `IEEE754 <http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=4610933>`_ définit le format de ces nombres sur 64 bits. + + buffer overflow + Problème à compléter + + garbage collector + Algorithme permettant de libérer la mémoire qui n'est plus utilisée notamment dans des langages tels que Java + + pointeur + à compléter + + adresse + à compléter + + C99 + Standard international définissant le langage C [C99]_ + + fichier header + à compléter + + segmentation fault + Erreur à l'exécution à compléter + + NOT + négation + Opération binaire logique. + + AND + conjonction logique + Opération binaire logique. + + OR + disjonction logique + Opération binaire logique. + + XOR + ou exclusif + Opération binaire logique. + + libc + Librairie C standard. Contient de nombreuses fonctions utilisables par les programmes écrits en langage C et décrites dans la troisième section des pages de manuel. Linux utilise la librairie GNU `glibc <http://www.gnu.org/software/libc/manual/>`_ qui contient de nombreuses extensions par rapport à la libraire standard. + + FSF + Free Software Foundation, http://www.fsf.org + + buffer overflow + à compléter + + portée + à compléter + + portée locale + à compléter + + portée globale + à compléter + + debugger + à compléter + + text + segment text + à compléter + + segment des données initialisées + à compléter + + segment des données non-initialisées + à compléter + + heap + tas + à compléter + + stack + pile + à compléter + + etext + à compléter + + memory leak + à compléter + + processus + Ensemble cohérent d'instructions utilisant une partie de la mémoire, initié par le système d'exploitation et exécuté sur un des processeurs du système. Le système d'exploitation libère les ressources qui lui sont allouées à la fin de son exécution. + + pid + process identifier + identifiant de processus. Sous Unix, chaque processus est identifié par un entier unique. Cet identifiant sert de clé d'accès à la :term:`table des processus`. Voir `getpid(2)`_ pour récupérer l'identifiant du processus courant. + + table des processus + Table contenant les identifiants (:term:`pid`) de tous les processus qui s'exécutent à ce moment sur un système Unix. Outre les identifiants, cette table contient de nombreuses informations relatives à chaque :term:`processus`. Voir également :term:`/proc` + + /proc + Sous Linux, représentation de l'information stockée dans la :term:`table des processus` sous la forme d'une arborescence directement accessible via les commandes du :term:`shell`. Voir `proc(5)`_ + + signal + mécanisme permettant la communication entre processus. Utilisé notamment pour arrêter un processus via la commande `kill(1)`_ + + von Neumann + Un des inventaires des premiers ordinateurs. A défini l'architecture de base des premiers ordinateurs qui est maintenant connue comme le modèle de von Neumann [Krakowiak2011]_ + + mémoire + à compléter + + SRAM + static RAM + Un des deux principaux types de mémoire. Dans une SRAM, l'information est mémorisée comme la présence ou l'absence d'un courant électrique. Les mémoires SRAM sont généralement assez rapides mais de faible capacité. Elles sont souvent utilisées pour construire des mémoires caches. + + DRAM + dynamic RAM + Un des deux principaux types de mémoire. Dans une DRAM, l'information est mémorisée comme la présence ou l'absence de charge dans un minuscule condensateur. Les mémoires DRAM sont plus lentes que les :term:`SRAM` mais ont une plus grande capacité. + + RAM + Random Access Memory + Mémoire à accès aléatoire. Mémoire permettant au processeur d'accéder à n'importe quelle donnée en connaissant son adresse. Voir :term:`DRAM` et :term:`SRAM`. + + + registre + Unité de mémoire intégrée au processeur. Les registres sont utilisés comme source ou destination pour la plupart des opérations effectuées par un processeur. + + hiérarchie de mémoire + Ensemble des mémoires utilisées sur un ordinateur. Depuis les registres jusqu'à la mémoire virtuelle en passant par la mémoire centrale et les mémoires caches. + + mémoire cache + Mémoire rapide de faible capacité. La mémoire cache peut stocker des données provenant de mémoires de plus grande capacité mais qui sont plus lentes, et exploite le :term:`principe de localité` en stockant de manière transparente les instructions et les données les plus récemment utilisées. Elle fait office d'interface entre le processeur et la mémoire principale et toutes les demandes d'accès à la mémoire principale passent par la mémoire cache, ce qui permet d'améliorer les performances de nombreux systèmes informatiques. + + principe de localité + Voir :term:`localité spatiale` et :term:`localité temporelle`. + + localité spatiale + à compléter + + localité temporelle + à compléter + + lignes de cache + à compléter + + write through + Technique d'écriture dans les mémoires caches. Toute écriture est faite simultanément en mémoire cache et en mémoire principale. Cela garantit la cohérence entre les deux mémoires mais réduit les performances. + + write back + Technique d'écriture dans les mémoires caches. Toute écriture est faite en mémoire cache. La mémoire principale n'est mise à jour que lorsque la donnée modifiée doit être retirée de la cache. Cette technique permet d'avoir de meilleures performances que :term:`write through` mais il faut faire parfois attention aux problèmes qui pourraient survenir sachant que la mémoire cache et la mémoire principale ne contiennent pas toujours exactement la même information. + + eip + pc + compteur de programme + instruction pointer + Registre spécial du processeur qui contient en permanence l'adresse de l'instruction en cours d'exécution. Le contenu de ce registre est incrémenté après chaque instruction et modifié par les instructions de saut. + + mode d'adressage + à compléter + + accumulateur + Registre utilisé dans les premiers processeurs comme destination pour la plupart des opérations arithmétiques et logiques. Sur l'architecture [IA32]_, le registre ``%eax`` est le successeur de cet accumulateur. + + bus + à compléter + + ligne de cache + à compléter. Voir notamment [McKenney2005]_ et [Drepper2007]_ + + write-back + à compléter + + program counter + à compléter + + makefile + à compléter + + fichier + à compléter + + fichier objet + à compléter + + linker + à compléter + + errno + à compléter + + loi de Moore + à compléter + + kHz + à compléter + + MHz + à compléter + + GHz + à compléter + + MIPS + Million d'instructions par seconde + + benchmark + à compléter + + multi-coeurs + à compléter + + multi-threadé + à compléter + + section critique + à compléter + + exclusion mutuelle + à compléter + + sureté + safety + à compléter + + liveness + vivacité + à compléter + + multitâche + multitasking + à compléter + + contexte + à compléter + + changement de contexte + à compléter + + interruption + à compléter + + scheduler + à compléter + + round-robin + à compléter + + livelock + à compléter + + opération atomique + à compléter + + deadlock + à compléter + + mutex + à compléter + + problème des philosophes + à compléter + + appel système + à compléter + + appel système bloquant + à compléter + + sémaphore + à compléter + + problèmes des readers-writers + à compléter + + inode + à compléter + + segment de données + à compléter + + problème des readers-writers + à compléter + + thread-safe + à compléter + + loi de Amdahl + à compléter + + static library + librairie statique + à compléter + + shared library + librairie dynamique + librairie partagée + à compléter + + kernel + à compléter + + mode utilisateur + à compléter + + mode protégé + à compléter + + processus père + à compléter + + processus fils + à compléter + + processus orphelin + à compléter + + processus zombie + à compléter + + filesystem + système de fichiers + à compléter + + descripteur de fichier + à compléter + + répertoire + à compléter + + secteur + à compléter + + répertoire courant + à compléter + + offset pointer + à compléter + + little endian + à compléter + + big endian + à compléter + + lien symbolique + à compléter + + lock + à compléter + + advisory lock + advisory locking + à compléter + + mandatory lock + mandatory locking + à compléter + + open file object + à compléter + + sémaphore nommé + à compléter + + appel système lent + à compléter + + handler + à compléter + + signal synchrone + à compléter + + signal asynchrone + à compléter + + interpréteur + à compléter + + MMU + Memory Management Unit + à compléter + + adresse virtuelle + à compléter + + mémoire virtuelle + à compléter + + SSD + Solid State Drive + Système de stockage de données s'appuyant uniquement sur de la mémoire flash. + + stratégie de remplacement de pages + à compléter + + page + à compléter + + table des pages + à compléter + + bit de validité + à compléter + + TLB + Translation Lookaside Buffer + à compléter + + Mémoire partagée + à compléter + + copy-on-write + à compléter + + adresse physique + à compléter + + page fault + défaut de page + à compléter + + file FIFO + De "First In, First Out". Le premier élement à entrer dans la file sera le premier à en sortir. (!= LIFO, "Last In First Out") + + dirty bit + bit de modification + à compléter + + reference bit + bit de référence + à compléter + + swapping + à compléter + + pagination + à compléter + + stdio + à compléter + + fifo + à compléter + + gnuth + à compléter + + partition de swap + à compléter + + stratégie de remplacement de pages + à compléter + + 2^64 + à compléter + + root + à compléter + + userid + à compléter \ No newline at end of file diff --git a/Exercices/incl_links.rst b/Theorie/incl_links.rst similarity index 100% rename from Exercices/incl_links.rst rename to Theorie/incl_links.rst diff --git a/Theorie/index.rst b/Theorie/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..6f1ace35810f5b4a8ab6a5e79195153a1f99de74 --- /dev/null +++ b/Theorie/index.rst @@ -0,0 +1,86 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012-2014 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + + +###################### +Systèmes informatiques +###################### + + +.. only:: html + + Ce site web contient la partie théorique du support du cours `SINF1252 <http://www.uclouvain.be/en-cours-2012-lsinf1252.html>`_ donné aux `étudiants en informatique <http://www.uclouvain.be/info.html>`_ à l'`Université catholique de Louvain <http://www.uclouvain.be>`_ (UCL). Les étudiants sont invités à ajouter leur commentaires en soumettant des patches via https://github.com/obonaventure/SystemesInformatiques . + + La version HTML est la préférable car elle contient des liens hypertextes vers les pages de manuel Linux qui font partie de la matière. D'autres formats sont possibles pour ceux qui veulent lire le document hors ligne : + + - `format epub <http://sites.uclouvain.be/SystInfo/distrib/SINF1252-Theorie.epub>`_ lisible sur tablettes style iPad ou Galaxy Tab + - `format pdf <http://sites.uclouvain.be/SystInfo/distrib/SINF1252-Theorie.pdf>`_ pour lecture via les logiciels Adobe ou pour impression + + + +Introduction +************* +.. toctree:: + :maxdepth: 2 + + intro + +Langage C +********* + +.. toctree:: + :maxdepth: 2 + + C/intro-C + C/datatypes + C/malloc + C/linker + +Structure des ordinateurs +************************* +.. toctree:: + :maxdepth: 2 + + Assembleur/memory + +Systèmes Multiprocesseurs +************************* +.. toctree:: + :maxdepth: 2 + + Threads/threads + Threads/threads2 + Threads/coordination + Threads/processus + +Fichiers +******** + +.. toctree:: + :maxdepth: 2 + + Fichiers/fichiers + Fichiers/fichiers-signaux + + +Mémoire virtuelle +***************** + +.. toctree:: + :maxdepth: 2 + + MemoireVirtuelle/vmem + + + +******* +Annexes +******* + +.. toctree:: + :maxdepth: 2 + + bib + glossaire + diff --git a/Theorie/intro.rst b/Theorie/intro.rst index 6939badb56c0939e839048f9fc36c08f8b2d9a3b..85a71ac5724e8184ade201b32eb6d0fff42fa2aa 100644 --- a/Theorie/intro.rst +++ b/Theorie/intro.rst @@ -122,7 +122,7 @@ Unix ayant été initialement développé pour manipuler des documents contenant - `sed(1)`_ : utilitaire permettant d'éditer, c'est-à -dire de modifier les caractères présents dans un flux de données. - `awk(1)`_ : utilitaire incluant un petit langage de programmation et qui permet d'écrire rapidement de nombreux programmes de manipulation de fichiers textes -La plupart des utilitaires fournis avec un système Unix ont été conçus pour être utilisés en combinaison avec d'autres. Cette combinaison efficace de plusieurs petits utilitaire est un des points forts des systèmes Unix par rapport à d'autres systèmes d'exploitation. +La plupart des utilitaires fournis avec un système Unix ont été conçus pour être utilisés en combinaison avec d'autres. Cette combinaison efficace de plusieurs petits utilitaires est un des points forts des systèmes Unix par rapport à d'autres systèmes d'exploitation. Shell @@ -222,7 +222,7 @@ Une description complète de `bash(1)`_ sort du cadre de ce cours. De nombreuses .. [#fbitreseau] Dans certaines applications, par exemple dans les réseaux informatiques, il peut être utile d'accéder à la valeur d'un bit particulier qui joue par exemple le rôle d'un drapeau. Celui-ci se trouve cependant généralement à l'intérieur d'une structure de données comprenant un ensemble de bits. -.. [#funix] Formellement, Unix est une marque déposée par l'`Open Group <http://www.opengroup.org>`_ un ensemble d'entreprises qui développent des standards dans le monde de l'informatique. La première version de Unix écrite en C date de 1973, http://www.unix.org/what_is_unix/history_timeline.html +.. [#funix] Formellement, Unix est une marque déposée par l'`Open Group <http://www.opengroup.org>`_, un ensemble d'entreprises qui développent des standards dans le monde de l'informatique. La première version de Unix écrite en C date de 1973, http://www.unix.org/what_is_unix/history_timeline.html .. [#ftermine] Certains processus sont lancés automatiquement au démarrage du système et ne se terminent qu'à son arrêt. Ces processus sont souvent appelés des `daemons`. Il peut s'agir de services qui fonctionnent en permanence sur la machine, comme par exemple un serveur web ou un `daemon` d'authentification. diff --git a/Exercices/man_links.rst b/Theorie/man_links.rst similarity index 100% rename from Exercices/man_links.rst rename to Theorie/man_links.rst diff --git a/_static/haiku.css b/_static/haiku.css index dbdcaf7b4cabd85fc984a310077efec29d55b8d2..5edeac7ec86dfa92be8f1257c10ca232ec4aec40 100644 --- a/_static/haiku.css +++ b/_static/haiku.css @@ -29,11 +29,12 @@ html { background: #FFF url(bg-page.png) top left repeat-x; } +/* font-family: Arial, Helvetica, sans-serif; */ + body { line-height: 1.5; margin: auto; padding: 0px; - font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; min-width: 59em; max-width: 60em; color: #333333; diff --git a/glossaire.rst b/glossaire.rst index 41221282b282012619e4f221185133abe688604c..8265e619567885155efbf888d828434fd5cf3f1b 100644 --- a/glossaire.rst +++ b/glossaire.rst @@ -195,13 +195,13 @@ Glossaire text segment text - à compléter + Zone de mémoire contenant les instructions qui sont exécutées par le micro-processeur. segment des données initialisées - à compléter + Zone de mémoire contenant l'ensemble des variables globales explicitement initialisées ainsi que les constantes et chaînes de caractères utilisée par le programme. segment des données non-initialisées - à compléter + Zone de mémoire contenant les variables non-initialisées. Celles-ci sont initialisées à 0 par le système d'exploitation. heap tas @@ -270,7 +270,7 @@ Glossaire Si une partie de la mémoire est utilisée par un programme à un moment donné, il est fort probable que cette partie soit réutilisée prochainement par le programme (par exemple lors de l'exécution d'une boucle). lignes de cache - à compléter + Plus petit élément de données qui peut être transféré entre la mémoire cache et la mémoire de niveau supérieur. write through Technique d'écriture dans les mémoires caches. Toute écriture est faite simultanément en mémoire cache et en mémoire principale. Cela garantit la cohérence entre les deux mémoires mais réduit les performances. @@ -285,7 +285,7 @@ Glossaire Registre spécial du processeur qui contient en permanence l'adresse de l'instruction en cours d'exécution. Le contenu de ce registre est incrémenté après chaque instruction et modifié par les instructions de saut. mode d'adressage - à compléter + Spécifie la façon dont est calculée l'adresse mémoire effective d'un opérande à partir de valeurs contenues dans des registres et de constantes contenues dans l'instruction ou ailleurs dans la machine. accumulateur Registre utilisé dans les premiers processeurs comme destination pour la plupart des opérations arithmétiques et logiques. Sur l'architecture [IA32]_, le registre ``%eax`` est le successeur de cet accumulateur. @@ -293,12 +293,6 @@ Glossaire bus Composant central d'une architecture de :term:`von Neumann` semblable à un canal permettant de transporter de l'information d'un composant à un l'autre. - ligne de cache - à compléter. Voir notamment [McKenney2005]_ et [Drepper2007]_ - - write-back - à compléter - program counter Registre du processeur qui contient l'adresse mémoire de l'instruction du programme en cours d'exécution. Il est incrémenté à chaque fois qu'une instruction est chargée et exécutée. @@ -342,22 +336,28 @@ Glossaire Section de code dans laquelle il ne doit jamais y avoir plus d'un thread simultanément. exclusion mutuelle - à compléter + Primitive de synchronisation utilisée pour éviter que des ressources partagées d'un système ne soient utilisées en même temps.Voir :term:'mutex' sureté safety - à compléter + Deux processus ne peuvent pas utiliser la même section critique simultanément. liveness vivacité - à compléter + Toutes les requêtes d'accès à la section critique sont garanties. + + fairness + équité + Les requêtes d'accès sont effectuées dans l'ordre d'appel. + multitâche multitasking - à compléter + Capacité de faire tourner plusieurs programmes simultanément en partageant les ressources de l'ordinateur. + contexte - à compléter + Ensemble des données utilisées par le thread en question. Ces données sont situées dans les registres du processeur sur lequel la tâche est exécutée, dans la zone de la mémoire utilisée par la tâche ou pour certains systèmes d'exploitation, dans des registres de contrôle stockant les informations nécessaires au système pour gérer ce processus. changement de contexte Processus d'enregistrement et de restauration de l'état d'un thread ou processus par le noyau pour que son exécution puisse reprendre ultérieurement. Un changement de contexte est par exemple effectué lorsque le noyau/scheduler provoque la transition d'un processus à un autre, ou lorsqu'une interruption force l'exécution d'une routine du noyau. @@ -372,7 +372,7 @@ Glossaire Dans le cadre du scheduler, il s'agit d'un algorithme qui alloue à tour de rôle un temps d'exécution égal à chaque processus sans distinction aucune. livelock - à compléter + Dans un programme concurrent, une situation de livelock est une situation de non-progression qui survient lorsque plusieurs threads ou processus concurrents changent continuellement d'état en simultanés et qu'aucuns ne progressent. opération atomique Opération élémentaire ne pouvant pas être divisée. @@ -384,31 +384,24 @@ Glossaire Primitive de synchronisation entre threads basé sur le principe d'exclusion mutuelle. Quand plusieurs threads veulent accéder à la même ressource ou section critique, un mutex peut protéger cette ressource ou section critique et assurer qu'un seul thread ne puisse y accèder à tout moment. problème des philosophes - à compléter + Problème sur le partage de ressources en informatique. Il concerne l'ordonnancement des processus et l'allocation des ressouces à ces derniers. appel système Permet à un programme de demander l'exécution d'un service fourni par le noyau du système d'exploitation. appel système bloquant - à compléter + Un appel sysème bloquant mets un processus en attente (état W) et ne le réveillera (état R) que lorsque cet appel système sera prêt à retourner sémaphore Mécanisme de synchronisation entre threads inventé par Edsger Dijkstra pour limiter le nombre de threads qui peuvent accèder de manière concurrente à une ressource partagée. problèmes des readers-writers - à compléter + Modélise un problème qui survient lorsque des threads (readers et writers) doivent accèder à une base de données. inode Structure de données contenant des informations (méta-données) relatives à un fichier sur certains systèmes de fichiers (Unix par exemple). Ces informations comportent notamment les permissions associées au fichier, l'utilisateur propriétaire du fichier, le groupe du propriétaire du fichier. Pour plus d'informations, voir la section `Système de fichier <http://sites.uclouvain.be/SystInfo/notes/Theorie/html/Fichiers/fichiers.html#systemes-de-fichiers>`_ . - - segment de données - à compléter - - problème des readers-writers - à compléter - thread-safe Un programme est considéré thread-safe s'il fonctionne correctement lors d'une éxecution simultannée par plusieurs threads.En particulier, le programme doit satisfaire le besoin pour plusieurs threads d'accéder à la même donnée partagée entre eux et le besoin pour une donnée partagée entre threads d'être accessible par un seul thread à un moment donné. En C, on utilise notamment les :term:`mutex` ou d'autres types de locks pour résoudre ce genre de problème. @@ -418,21 +411,21 @@ Glossaire static library librairie statique - à compléter + Librairie destinée à être copiée dans les programmes qui l'utilisent lors de la constructions de ces derniers. shared library librairie dynamique librairie partagée - à compléter + Librairie destinée à être associée aux programmes où ils sont exécutés. Avec une librairie dynamique, la même copie de la librairie peut être utilisée par plusieurs programmes. kernel à compléter mode utilisateur - à compléter + En mode utilisateur, le code exécuté n'a pas la possibilité d'accéder directement au matériel ou à la mémoire. Il faut passer par les API du système pour accéder le matériel ou la mémoire. Grâce à cette protection, qui est une sorte d'isolation, les crashs en mode utilisateur sont toujours récupérable. mode protégé - à compléter + En mode protégé, le code exécuté a un accès complet au matériel sous-jacent. Il peut exécuter n'importe quelle instruction CPU et référencer n'importe quelle adresse mémoire. processus père Processus ayant lancé un autre processus (:term:`processus fils`) suite à un appel à la fonction fork(). @@ -448,120 +441,120 @@ Glossaire filesystem système de fichiers - à compléter + Facon de stocker les informations et de les organiser dans des fichiers sur ce que l'on appelle des mémoires secondaires (exemple : disque dur, SSD, CD-ROM, USB,...). descripteur de fichier - à compléter + Clés abstraite pour accéder à un fichier. répertoire - à compléter + Fichier spécial contenant les noms et inodes d'autres fichiers et répertoires. secteur - à compléter + Plus petite unité physique de stockage pour un support de données. répertoire courant - à compléter + Répertoire dans lequel le processus en cours d'exécution ouvrira les fichiers via open. offset pointer - à compléter + Valeur entière représentant le déplacement en mémoire nécessaire, par rapport à une adresse de référence pour atteindre une autre adresse. C'est la distance séparant deux emplacements mémoire. little endian - à compléter + L'octet de poids le plus faible est enregistré à l'adresse mémoire la plus petite, l'octet de poids supérieur est enregistré à l'adresse mémoire suivante et ainsi de suite. big endian - à compléter + L'octet de poids le plus fort est enregistré à l'adresse mémoire la plus petite, l'octet de poids inférieur est enregistré à l'adresse mémoire suivante et ainsi de suite. lien symbolique à compléter lock - à compléter + Permet à un processus d'obtenir l'accès exclusif à un fichier ou une partie de fichier. advisory lock advisory locking - à compléter + Les processus doivent vérifier eux-mêmes que les accès qu'ils effectuent ne violent pas les locks qui ont été associés aux différents fichier. mandatory lock mandatory locking - à compléter + Dans ce cas, les processus placent des locks sur certains fichiers ou zones de fichiers et le système d’exploitation vérifie qu’aucun accès fait aux fichiers avec les appels systèmes standards ne viole ces locks. open file object - à compléter + Contient toutes les informations qui sont nécessaires au noyau pour pouvoir effectuer les opérations de manipulation d'un fichier ouvert par un processus. sémaphore nommé - à compléter + Sémaphore utilisant une zone mémoire qui est gérée par le noyau et qui peut être utilisée par plusieurs processus. appel système lent - à compléter + Appel système dont l'exécution peut être interrompue par la réception d'un signal. (Exemple : open(2), write(2), sendto(2), recvfrom(2), sendmsg(2), recvmsg(2), wait(2) ioctl(2)) handler - à compléter + Un handler est associé à un signal et est exécuté dès que ce signal survient. signal synchrone - à compléter + Signal qui a été directement causé par l'exécution d'une instruction du processus. signal asynchrone - à compléter + Signal qui n’a pas été directement causé par l’exécution d’une instruction du processus. interpréteur - à compléter + Outil ayant pour tâche d'analyser, de traduire et d'exécuter les programmes écrits dans un langage informatique. MMU Memory Management Unit - à compléter + Traduit toute adresse virtuelle en adresse physique. adresse virtuelle - à compléter + Adresse qui est utilisée à l’intérieur d’un programme mémoire virtuelle - à compléter + Repose sur l'utilisation de traduction des adresses virtuelles en adresses physiques. SSD Solid State Drive Système de stockage de données s'appuyant uniquement sur de la mémoire flash. page - à compléter + Bloc de mémoire virtuelle. table des pages - à compléter + Structure de données utilisée pour stocker les liens entre adresses virtuelles et adresses physiques. bit de validité - à compléter + Permet de voir la validité ou non d'un numéro de frame à la page actuelle. Si celui-ci est à 0, cela signigie que le numéro de frame est invalide. TLB Translation Lookaside Buffer - à compléter + Mémoire cache du processeur utilisée par l'unité de gestion mémoire (:term:'MMU') dans le but d'accélérer la traduction des adresses virtuelles en adresses physiques. Mémoire partagée - à compléter + Moyen de partager des données entre différents processus : une même zone de la mémoire vive est accédée par plusieurs processus. copy-on-write à compléter adresse physique - à compléter + Adresse utilisée par des puces de RAM pour les opérations d'écriture et de lecture. page fault défaut de page - à compléter + Erreur de page introuvable en mémoire. Plus précisément, interruption qui suspend l'exécution d'un processus pour éventuellement lui libérer de la mémoire vive en la déchargeant dans la mémoire virtuelle, mais surtout le charger dans la RAM ensuite, en modifiant son bit de validation à un. file FIFO De "First In, First Out". Le premier élement à entrer dans la file sera le premier à en sortir. (!= LIFO, "Last In First Out") dirty bit bit de modification - à compléter + Bit indiquant si une page a été modifiée depuis son chargement en mémoire vive. Il est donc égal à zéro si un processus a déjà figuré dans la mémoire virtuelle, et à un si la page a été modifiée depuis son chargement ou si elle est nouvellement allouée. reference bit bit de référence - à compléter + Bit indiquant si une page a été accédée récemment, il est remis à 0 régulièrement. swapping - à compléter + Toutes les données appartenant au processus seront stockées en mémoire de masse. pagination - à compléter + Technique permettant de découper la mémoire vive en zones (:term:'page') et change la correspondance entre mémoire virtuelle et mémoire physique. stratégie de remplace de pages - à compléter + Définit quelle page doit être préférentiellement retirée de la mémoire RAM et placée sur le dispositif de stockage. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..06980811aa5260912992abb13a18f4248ae88941 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +sphinx==1.8.3 diff --git a/travis.sh b/travis.sh new file mode 100755 index 0000000000000000000000000000000000000000..d79b5758cb510b1d27bf20e74d9c1055d0a11aeb --- /dev/null +++ b/travis.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# on error exit +set -e +# Flags used here, not in `make html`: +# -n Run in nit-picky mode. Currently, this generates warnings for all missing references. +# -W Turn warnings into errors. This means that the build stops at the first warning and sphinx-build exits with exit status 1. +# -N Do not emi colors +# -T output full traceback +# --keep-going continue the processing after a warning +cd Theorie +echo "**** Theorie ****" +sphinx-build -nWNT --keep-going -b html . /tmp +cd ../Outils +echo "**** Outils ****" +sphinx-build -nWNT --keep-going -b html . /tmp +cd ../Exercices +echo "**** Exercices ****" +#sphinx-build -nWNT --keep-going -b html . /tmp +cd QCM +echo "**** QCM ****" +#make +cd ../.. \ No newline at end of file diff --git a/website/blog.rst b/website/blog.rst new file mode 100644 index 0000000000000000000000000000000000000000..f4623acff22076d5af2a33d28f5497fd9bcd7cb8 --- /dev/null +++ b/website/blog.rst @@ -0,0 +1,16 @@ +.. -*- coding: utf-8 -*- +.. Copyright |copy| 2012-2014 by `Olivier Bonaventure <http://inl.info.ucl.ac.be/obo>`_, Christoph Paasch et Grégory Detal +.. Ce fichier est distribué sous une licence `creative commons <http://creativecommons.org/licenses/by-sa/3.0/>`_ + +Blog +==== + +Un blog est associé au cours. Il est hébergé sur `github <https://www.github.com`_ et est accessible depuis l'URL +https://obonaventure.github.io/SystInfoBlog + +Il sera alimenté par les étudiant-e-s qui suivent le cours avec des informations qu'ils-elles considèrent comme +utiles. + + + + diff --git a/website/index.rst b/website/index.rst index b93fa670a74290352f3e0f2b65c6d2dd85b9a836..3606c974ff9a8787e942e887316b59d0b15d93b5 100644 --- a/website/index.rst +++ b/website/index.rst @@ -23,4 +23,5 @@ Vous pouvez accéder aux différentes parties du syllabus via les liens dans la Théorie <theorie> Exercices <exercices> Outils <outils> + Blog <blog> Auteurs <auteurs>