{"id":1805,"date":"2012-03-21T23:18:28","date_gmt":"2012-03-21T22:18:28","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=1805"},"modified":"2012-03-21T23:18:28","modified_gmt":"2012-03-21T22:18:28","slug":"envoi-dun-signal-vers-un-processus-depuis-le-kernel","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/03\/21\/envoi-dun-signal-vers-un-processus-depuis-le-kernel\/","title":{"rendered":"Envoi d&rsquo;un signal vers un processus depuis le kernel"},"content":{"rendered":"<p style=\"text-align: justify;\">Nous avons examin\u00e9 r\u00e9cemment le <a title=\"R\u00e9veil d\u2019une t\u00e2che utilisateur depuis un timer kernel\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/03\/12\/reveil-dune-tache-utilisateur-depuis-un-timer\/\">temps de r\u00e9veil d&rsquo;une t\u00e2che endormie dans un appel-syst\u00e8me<\/a>. Je voulais compl\u00e9ter cette exp\u00e9rience en m&rsquo;int\u00e9ressant au passage d&rsquo;un signal depuis le noyau vers l&rsquo;espace utilisateur. Nous allons plus particuli\u00e8rement mesurer le temps d&rsquo;activation d&rsquo;un processus lorsqu&rsquo;un signal temps r\u00e9el lui est envoy\u00e9 depuis le noyau.<\/p>\n<p>\n<!--more-->\n<\/p>\n<h1>Module du noyau<\/h1>\n<p style=\"text-align: justify;\">Le petit module ci-dessous d\u00e9clare un nouveau p\u00e9riph\u00e9rique qui appara\u00eetra sous forme de fichier sp\u00e9cial dans <code>\/dev\/<\/code>. Lorsqu&rsquo;un processus ouvre ce fichier, la structure <code>task_struct<\/code> qui le repr\u00e9sente &#8211; point\u00e9e par la variable globale <code>current<\/code> au moment de l&rsquo;appel syst\u00e8me <code>open()<\/code> &#8211; est m\u00e9moris\u00e9e. Un timer, d\u00e9clench\u00e9 tous les dixi\u00e8mes de seconde, enverra alors un signal <code>SIGRTMAX<\/code> \u00e0 ce processus jusqu&rsquo;\u00e0 ce qu&rsquo;il referme le fichier sp\u00e9cial.<\/p>\n<p style=\"text-align: justify;\">En accompagnement d&rsquo;un signal temps-r\u00e9el, il est possible de transmettre une union <code>sigval_t<\/code> contenant soit un entier soit un pointeur. Nous allons transmettre un entier contenant la partie \u00ab\u00a0nanosecondes\u00a0\u00bb de l&rsquo;heure actuelle.<\/p>\n<p style=\"text-align: justify;\">Voici le code du module <strong><code>signal-sur-timer.c<\/code><\/strong>. L&rsquo;archive contenant les codes cource <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-03-26\/signal-kernel.tar.bz2\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-03-26\/signal-kernel.tar.bz2\">se trouve ici<\/a>.<\/p>\n<pre>#include &lt;linux\/interrupt.h&gt;\n#include &lt;linux\/version.h&gt;\n#include &lt;linux\/device.h&gt;\n#include &lt;linux\/module.h&gt;\n#include &lt;linux\/sched.h&gt;\n#include &lt;linux\/cdev.h&gt;\n#include &lt;linux\/fs.h&gt;\n\n#include &lt;asm\/uaccess.h&gt;\n\nstatic dev_t          dev_reveil;\nstatic struct cdev    cdev_reveil;\nstatic struct class * class_reveil = NULL;\n\nstruct timer_list <strong>timer_reveil<\/strong>;\nstatic void timer_function(unsigned long);\n\nstatic int open_reveil  (struct inode *, struct file *);\nstatic int flush_reveil (struct file *,  fl_owner_t);\n\nstatic struct file_operations fops_reveil = {\n    .owner   =  THIS_MODULE,\n    .open    =  open_reveil,\n    .flush   =  flush_reveil,\n};\n\nstatic int __init <strong>init_reveil<\/strong> (void)\n{\n    int erreur;\n\n    erreur = <strong>alloc_chrdev_region<\/strong>(&amp; dev_reveil, 0, 1, THIS_MODULE-&gt;name);\n    if (erreur &lt; 0)\n        return erreur;\n\n    class_reveil = <strong>class_create<\/strong>(THIS_MODULE, \"classe-signal\");\n    if (IS_ERR(class_reveil)) {\n        unregister_chrdev_region(dev_reveil, 1);\n        return -EINVAL;\n    }\n    <strong>device_create<\/strong>(class_reveil, NULL, dev_reveil,\n                  NULL, THIS_MODULE-&gt;name);\n\n    cdev_init(&amp; cdev_reveil, &amp; fops_reveil);\n\n    erreur = cdev_add(&amp; cdev_reveil, dev_reveil, 1);\n    if (erreur != 0) {\n        device_destroy(class_reveil, dev_reveil);\n        class_destroy(class_reveil);\n        unregister_chrdev_region(dev_reveil, 1);\n        return erreur;\n    }\n    <strong>init_timer<\/strong>(&amp; timer_reveil);\n    timer_reveil.function = timer_function;\n    timer_reveil.expires  = HZ;\n    <strong>add_timer<\/strong>(&amp; timer_reveil);\n    return 0;\n}\n\nstatic void __exit <strong>exit_reveil<\/strong> (void)\n{\n    del_timer(&amp; timer_reveil);\n    cdev_del(&amp; cdev_reveil);\n    device_destroy(class_reveil, dev_reveil);\n    class_destroy(class_reveil);\n    unregister_chrdev_region(dev_reveil, 1);\n}\n\nstatic struct task_struct * <strong>task_reveil = NULL<\/strong>;\n\nstatic int <strong>open_reveil<\/strong>(struct inode * ind, struct file * filp)\n{\n    task_reveil = <strong>current<\/strong>;\n    return 0;\n}\n\nstatic int <strong>flush_reveil<\/strong>(struct file * fil,  fl_owner_t id)\n{\n    task_reveil = NULL;\n    return 0;\n}\n\nstatic void <strong>timer_function<\/strong>(unsigned long unused)\n{\n    struct siginfo info;\n    struct timespec ts;\n\n    <strong>ktime_get_real_ts<\/strong>(&amp; ts);\n\n    info.si_signo = SIGRTMAX;\n    info.si_errno = 0;\n    info.si_code = SI_QUEUE;\n    info.si_pid = 0;\n    <strong>info.si_int = ts.tv_nsec<\/strong>;\n    if (task_reveil != NULL)\n        <strong>send_sig_info(<\/strong>SIGRTMAX, &amp; info, task_reveil);\n\n    mod_timer(&amp; timer_reveil, jiffies + HZ\/10);\n}\n\nmodule_init(init_reveil);\nmodule_exit(exit_reveil);\nMODULE_LICENSE(\"GPL\");<\/pre>\n<p style=\"text-align: justify;\">Nous pouvons compiler ce programme et le charger. Pour savoir sur quel CPU se d\u00e9clenchera le timer, je vais utiliser la commande shell <code>taskset<\/code> au moment du chargement du module.<\/p>\n<pre># <strong>taskset -c 0 insmod .\/signal-sur-timer.ko <\/strong>\n# <strong>ls \/sys\/class\/<\/strong>\nata_device  bdi  <span style=\"text-decoration: underline;\">classe-signal<\/span> [...]\n# <strong>ls \/sys\/class\/classe-signal\/<\/strong>\nsignal_sur_timer\n# <strong>ls \/sys\/class\/classe-signal\/signal_sur_timer<\/strong>\ndev  power  subsystem  uevent\n# <strong>cat \/sys\/class\/classe-signal\/signal_sur_timer\/dev<\/strong>\n250:0\n# <strong>ls -l \/dev\/signal_sur_timer<\/strong>\ncrw------- 1 root root 250, 0 2012-03-22 07:11 \/dev\/signal_sur_timer\n#<\/pre>\n<h1>\u00a0Programme d&rsquo;attente du signal<\/h1>\n<p style=\"text-align: justify;\">Le processus\u00a0 qui recevra le signal dans l&rsquo;espace utilisateur va \u00e9galement lire l&rsquo;heure et calculer la diff\u00e9rence avec celle re\u00e7ue depuis le noyau. Comme nous n&rsquo;avons pas transmis le champ \u00ab\u00a0secondes\u00a0\u00bb de l&rsquo;heure, mais seulement le compl\u00e9ment en nanosecondes, il faudra g\u00e9rer un \u00e9ventuel d\u00e9bordement en rajoutant un milliard de secondes.<\/p>\n<p style=\"text-align: justify;\">Le programme s&rsquo;arr\u00eatera automatiquement au bout de 1000 signaux (1 minute 40 secondes, car les signaux surviennent tous les dixi\u00e8mes de secondes). La dur\u00e9e entre le d\u00e9clenchement du timer noyau et l&rsquo;activation du processus utilisateur est affich\u00e9e sur la sortie standard.<\/p>\n<pre><strong>attente-signal.c:<\/strong>\n#include &lt;fcntl.h&gt;\n#include &lt;signal.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;time.h&gt;\n#include &lt;unistd.h&gt;\n\nvoid <strong>handler_sigrtmax<\/strong>(int num, siginfo_t * info, void * unused)\n{\n    static int compteur = 0;\n    struct timespec ts;\n    long int duree;\n    <strong>clock_gettime<\/strong>(CLOCK_REALTIME, &amp; ts);\n\n    if (info != NULL) {\n        <strong>duree<\/strong> = ts.tv_nsec - info-&gt;si_int;\n        if (duree &lt; 0)\n            duree += 1000000000;\n    }\n    <strong>fprintf<\/strong>(stdout, \"%ldn\", <strong>duree<\/strong>);\n    compteur ++;\n    if (compteur == 1000)\n        exit(0);\n}\n\nint main(int argc, char * argv[])\n{\n    int fd;\n    struct sigaction action;\n\n    sigfillset(&amp; action.sa_mask);\n    action.sa_sigaction = handler_sigrtmax;\n    action.sa_flags = SA_SIGINFO;\n    <strong>sigaction<\/strong>(<strong>SIGRTMAX<\/strong>, &amp; action, NULL);\n\n    if ((argc != 2) || ((fd = open(argv[1], O_RDONLY)) &lt; 0)) {\n        fprintf(stderr, \"usage: %s fichier-spcialn\", argv[0]);\n        exit(EXIT_FAILURE);\n    }\n\n    while (1) {\n        <strong>pause()<\/strong>;\n    }\n    return EXIT_FAILURE;\n}<\/pre>\n<p style=\"text-align: justify;\">On notera que dans le corps principal du programme, celui-ci reste endormi en permanence en attente du signal suivant.<\/p>\n<h1 style=\"text-align: justify;\">Premiers r\u00e9sultats<\/h1>\n<p style=\"text-align: justify;\">Avant d&rsquo;ex\u00e9cuter notre programme, nous allons fixer la fr\u00e9quence CPU des deux coeurs afin d&rsquo;obtenir des r\u00e9sultats plus constants.<\/p>\n<pre># <strong>echo userspace &gt; \/sys\/devices\/system\/cpu\/cpu0\/cpufreq\/scaling_governor<\/strong>\n# <strong>echo userspace &gt; \/sys\/devices\/system\/cpu\/cpu1\/cpufreq\/scaling_governor<\/strong>\n# <strong>cat \/sys\/devices\/system\/cpu\/cpu0\/cpufreq\/scaling_max_freq &gt; \/sys\/devices\/system\/cpu\/cpu0\/cpufreq\/scaling_setspeed<\/strong>\n# <strong>cat \/sys\/devices\/system\/cpu\/cpu1\/cpufreq\/scaling_max_freq &gt; \/sys\/devices\/system\/cpu\/cpu1\/cpufreq\/scaling_setspeed<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\">Ex\u00e9cutons-le une premi\u00e8re fois, sur un CPU diff\u00e9rent du timer.<\/p>\n<pre># <strong>taskset -c 1 .\/attente-signal \/dev\/signal_sur_timer &gt; resultats-1.txt<\/strong>\n# <strong>cat resultats-1.txt<\/strong>\n43131\n30878\n101946\n137725\n30878\n31858\n29898\n27447\n31369\n31858\n32348\n34309\n133315\n179877\n32838\n[...]\n30388\n29897\n29408\n27447\n#<\/pre>\n<p style=\"text-align: justify;\">Pour analyser les r\u00e9sultats, je vais utiliser quelques scripts que j&rsquo;ai d\u00e9velopp\u00e9 pour mon livre \u00ab\u00a0<em>Solutions temps r\u00e9el sous Linux<\/em>\u00a0\u00bb (\u00e0 para\u00eetre tr\u00e8s prochainement). Ils seront disponibles dans quelques jours avec les sources des exemples du livre.<\/p>\n<pre># <strong>calculer-statistiques &lt; resultats-1.txt<\/strong>\n Nb mesures = 1000\n Minimum = 22055\n Maximum = 1631636\n Moyenne = 46002\n Ecart-type = 66924\n# <strong>calculer-histogramme 100 0 3000000 &lt; resultats-1.txt &gt; histo-1.txt<\/strong>\n# <strong>afficher-histogramme.sh histo-1.txt \"Attente signal - CPU diff\u00e9rents\"<\/strong>\n#<\/pre>\n<p style=\"text-align: center;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1811\" title=\"Figure 1 - Activation d'un processus par un signal du kernel\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-1-300x225.png\" alt=\"Figure 1 - Activation d'un processus par un signal du kernel\" width=\"300\" height=\"225\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Ceci nous fournit une premi\u00e8re figure avec la dur\u00e9e d&rsquo;activation en abscisse et en ordonn\u00e9e le nombre d&rsquo;activations observ\u00e9es (l&rsquo;\u00e9chelle est logarithmique).<\/p>\n<p style=\"text-align: justify;\">Sur la figure 1, nous observons que l&rsquo;essentiel des temps d&rsquo;activation sont inf\u00e9rieurs \u00e0 500 microsecondes (500000 nanosecondes), mais qu&rsquo;il y a des pointes jusqu&rsquo;\u00e0 1631 microsecondes, soit 1,6 millisecondes.<\/p>\n<p style=\"text-align: justify;\">La moyenne s&rsquo;\u00e9tablit \u00e0 46002 nanosecondes, soit 46 microsecondes.<\/p>\n<p style=\"text-align: justify;\">R\u00e9it\u00e9rons cette exp\u00e9rience en ex\u00e9cutons le processus en attente sur le m\u00eame CPU que le timer du kernel.<\/p>\n<pre># <strong>calculer-statistiques &lt; resultats-2.txt<\/strong>\n Nb mesures = 1000\n Minimum = 15194\n Maximum = 3102998\n Moyenne = 39288\n Ecart-type = 113346\n#<\/pre>\n<p style=\"text-align: justify;\">Nous remarquons que la dur\u00e9e maximale a augment\u00e9, ce qui nous oblige \u00e0 allonger l\u00e9g\u00e8rement l&rsquo;axe des abscisses pour notre figure.<\/p>\n<pre># <strong>calculer-histogramme 100 0 3200000 &lt; resultats-2.txt &gt; histo-2.txt<\/strong>\n# <strong>afficher-histogramme.sh histo-2.txt \"Attente signal - M\u00eame CPU\"<\/strong>\n#<\/pre>\n<p>&nbsp;<\/p>\n<div id=\"attachment_1814\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1814\" class=\"size-medium wp-image-1814 \" title=\"Figure 2 - Activation d'un processus par un signal kernel - M\u00eame CPU\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-2-300x225.png\" alt=\"Figure 2 - Activation d'un processus par un signal kernel - M\u00eame CPU\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1814\" class=\"wp-caption-text\">Figure 2 - Activation d&#39;un processus par un signal kernel - M\u00eame CPU<\/p><\/div>\n<p style=\"text-align: justify;\">La figure montre quelques activations sensiblement retard\u00e9es, ce qui est typique d&rsquo;une ex\u00e9cution sous un ordonnancement temps partag\u00e9. Toutefois, nous pouvons remarquer que la valeur moyenne est meilleure (39 microsecondes contre 46 microsecondes pr\u00e9c\u00e9demment).<\/p>\n<p style=\"text-align: justify;\">En outre, la figure pr\u00e9sente un meilleur regroupement des donn\u00e9es sur la gauche du graphique, la plupart des activations \u00e9tant survenues dans le premier intervalle du graphique.<\/p>\n<p style=\"text-align: justify;\">Nous pouvons en conclure que l&rsquo;activation par un signal est plus efficace si le code \u00e9metteur et le processus r\u00e9cepteur s&rsquo;ex\u00e9cutent sur le m\u00eame CPU.<\/p>\n<p style=\"text-align: justify;\">Pour d\u00e9passer les limites de l&rsquo;ordonnancement temps partag\u00e9, nous pouvons recommencer notre mesure en passant le processus r\u00e9cepteur en temps r\u00e9el gr\u00e2ce la commande shell <code>chrt<\/code>.<\/p>\n<pre># <strong>taskset -c 0 chrt -f 40  .\/attente-signal \/dev\/signal_sur_timer &gt; resultats-3.txt<\/strong>\n# <strong>calculer-statistiques &lt; resultats-3.txt<\/strong>\n Nb mesures = 1000\n Minimum = 20096\n Maximum = 212225\n Moyenne = 47692\n Ecart-type = 37429\n#<\/pre>\n<p style=\"text-align: justify;\">La valeur moyenne est proche de la premi\u00e8re mesure, mais la valeur maximale est bien meilleure, nous allons \u00ab\u00a0zoomer\u00a0\u00bb sensiblement l&rsquo;axe des abscisses de notre figure.<\/p>\n<pre># <strong>calculer-histogramme 100 0 250000 &lt; resultats-3.txt &gt; histo-3.txt<\/strong>\n# <strong>afficher-histogramme.sh histo-3.txt \"Attente signal - Temps r\u00e9el\"<\/strong>\n#<\/pre>\n<div id=\"attachment_1815\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-3.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1815\" class=\"wp-image-1815 \" title=\"Figure 3 - Activation d'un processus temps r\u00e9el par un signal kernel\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-3-300x225.png\" alt=\"Figure 3 - Activation d'un processus temps r\u00e9el par un signal kernel\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1815\" class=\"wp-caption-text\">Figure 3 - Activation d&#39;un processus temps r\u00e9el par un signal kernel<\/p><\/div>\n<p style=\"text-align: justify;\">Cette fois, la plupart des mesures sont en-dessous de 150 microsecondes, et seules quelques unes se trouvent dans la zone entre 150 et 212 microsecondes. Nous nous rapprochons des performances attendues sur un syst\u00e8me temps r\u00e9el. Notons que ces exp\u00e9riences sont men\u00e9es sur un syst\u00e8me avec un noyau 3.0 g\u00e9n\u00e9rique provenant d&rsquo;une distribution classique. Les r\u00e9sultats avec un noyau modifi\u00e9 par le patch Linux-rt seraient probablement meilleurs (je ferai l&rsquo;essai dans quelques jours et posterai les r\u00e9sultats ici).<\/p>\n<h1>Notification de processus actif<\/h1>\n<p style=\"text-align: justify;\">Dans cette premi\u00e8re \u00e9tape, nous avons laiss\u00e9 notre processus endormi dans un appel syst\u00e8me <code>pause()<\/code>, dont il n&rsquo;\u00e9merge que pour ex\u00e9cuter le handler du signal re\u00e7u avant de se rendormir. Mais l&rsquo;int\u00e9r\u00eat d&rsquo;un signal est avant tout sa possibilit\u00e9 de notification asynchrone. Autrement dit, il n&rsquo;est pas n\u00e9cessaire d&rsquo;\u00eatre en attente bloquante. Le processus peut tr\u00e8s bien r\u00e9aliser des op\u00e9rations de calcul ou de traitement des donn\u00e9es, d\u00e8s que le signal lui sera d\u00e9livr\u00e9, le programme d\u00e9routera son ex\u00e9cution pour se brancher sur le gestionnaire de signal avant de reprendre son travail comme pr\u00e9c\u00e9demment.<\/p>\n<p style=\"text-align: justify;\">Dans notre nouvelle exp\u00e9rience, nous allons simplement modifier la fin de la fonction <code>main()<\/code>, ainsi.<\/p>\n<pre><strong>boucle-et-signal.c:<\/strong>\n#include &lt;fcntl.h&gt;\n#include &lt;signal.h&gt;\n#include &lt;stdio.h&gt;\n[...]\nint main(int argc, char * argv[])\n{\n    [...]\n    while (1) {\n        ;\n    }\n    return EXIT_FAILURE;\n}<\/pre>\n<p style=\"text-align: justify;\">Premi\u00e8re ex\u00e9cution, comme pr\u00e9c\u00e9demment, commen\u00e7ons par lancer le processus sur un autre CPU que celui du timer du kernel.<\/p>\n<pre># <strong>taskset -c 1 .\/boucle-et-signal \/dev\/signal_sur_timer &gt; resultats-4.txt<\/strong>\n# <strong>cat resultats-4.txt<\/strong>\n24507\n12743\n10293\n8822\n10293\n8822\n9802\n8823\n9803\n[...]\n10100065\n22056\n42641\n17154\n18135\n18625\n18135\n20096\n18625\n18135\n18134\n119101\n119101\n119591\n117140\n14704\n12743\n# <strong>calculer-statistiques &lt; resultats-4.txt<\/strong>\n Nb mesures = 1000\n Minimum = 8332\n Maximum = 10100065\n Moyenne = 28521\n Ecart-type = 326958\n#<\/pre>\n<p>Les r\u00e9sultats sont sensiblement meilleurs en moyenne que pr\u00e9c\u00e9demment, c&rsquo;est normal car le processus \u00e9tant actif, le processeur ne peut pas se mettre en veille et la d\u00e9livrance du signal est d&rsquo;autant plus efficace.<br \/>\nToutefois la dur\u00e9e maximale a bien empir\u00e9&nbsp;: plus de 10ms&nbsp;! Ceci est \u00e9galement normal car le processus s&rsquo;ex\u00e9cute sous un ordonnancement temps partag\u00e9.<\/p>\n<p>Relan\u00e7ons-le en temps r\u00e9el, sur le m\u00eame CPU que le timer du kernel.<\/p>\n<pre># <strong>taskset -c 0 chrt -f 40  .\/boucle-et-signal \/dev\/signal_sur_timer &gt; resultats-5.txt<\/strong>\n# <strong>calculer-statistiques &lt; resultats-5.txt<\/strong>\n Nb mesures = 1000\n Minimum = 2940\n Maximum = 328386\n Moyenne = 20025\n Ecart-type = 37036\n#<\/pre>\n<div id=\"attachment_1821\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-4.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1821\" class=\"size-medium wp-image-1821 \" title=\"Figure 4 - Signal sur processus actif en temps-r\u00e9el\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/03\/figure-4-300x225.png\" alt=\"Figure 4 - Signal sur processus actif en temps-r\u00e9el\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1821\" class=\"wp-caption-text\">Figure 4 - Signal sur processus actif en temps-r\u00e9el<\/p><\/div>\n<p style=\"text-align: justify;\">Nous voyons sur la figure 4 que la majorit\u00e9 des signaux sont trait\u00e9s en moins de 120 microsecondes, et que seules quelques exceptions peuvent \u00eatre retard\u00e9es jusqu&rsquo;\u00e0 328 microsecondes.<\/p>\n<p style=\"text-align: justify;\">Il faudrait laisser fonctionner le processus beaucoup plus longtemps, avec une charge syst\u00e8me importante pour s&rsquo;assurer de la dur\u00e9e maximale d&rsquo;activation d&rsquo;un processus par un signal provenant du kernel. Toutefois, je pense que l&rsquo;ordre de grandeur (quelques centaines de microsecondes) est celui que l&rsquo;on peut attendre avec Linux <em>vanilla<\/em>.<\/p>\n<p style=\"text-align: justify;\">Nous pourrions probablement obtenir des r\u00e9sultats similaires avec un noyau contenant le patch Linux-rt, voire meilleurs en ce qui concerne les cas extr\u00eames.<\/p>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">En conclusion je pense que le r\u00e9veil ou l&rsquo;activation d&rsquo;un processus par un signal provenant du kernel, pour le notifier par exemple de l&rsquo;occurrence d&rsquo;une interruption mat\u00e9rielle, est une alternative \u00e0 la mise en sommeil sur un appel syst\u00e8me bloquant &#8211; <code>read()<\/code>, <code>ioctl()<\/code>, <code>poll()<\/code>&#8230; &#8211; qu&rsquo;il faut consid\u00e9rer lors de la mise au point d&rsquo;un syst\u00e8me interactif devant r\u00e9pondre \u00e0 des \u00e9v\u00e9nements externes.<\/p>\n<p>&nbsp;<\/p>","protected":false},"excerpt":{"rendered":"<p>Nous avons examin&eacute; r&eacute;cemment le temps de r&eacute;veil d&rsquo;une t&acirc;che endormie dans un appel-syst&egrave;me. Je voulais compl&eacute;ter cette exp&eacute;rience en m&rsquo;int&eacute;ressant au passage d&rsquo;un signal depuis le noyau vers l&rsquo;espace utilisateur. Nous allons plus particuli&egrave;rement mesurer le temps d&rsquo;activation d&rsquo;un processus lorsqu&rsquo;un signal temps r&eacute;el lui est envoy&eacute; depuis le noyau.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,8,14],"tags":[],"class_list":["post-1805","post","type-post","status-publish","format-standard","hentry","category-embarque","category-linux-2","category-temps-reel"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1805","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=1805"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1805\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=1805"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=1805"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=1805"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}