{"id":3998,"date":"2014-04-05T02:43:47","date_gmt":"2014-04-05T01:43:47","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=3998"},"modified":"2014-05-03T03:24:35","modified_gmt":"2014-05-03T02:24:35","slug":"utiliser-un-appel-systeme-inconnu-de-la-libc","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2014\/04\/05\/utiliser-un-appel-systeme-inconnu-de-la-libc\/","title":{"rendered":"Utiliser un appel-syst\u00e8me inconnu de la libC"},"content":{"rendered":"<p style=\"text-align: justify;\">Lundi dernier, Linus a publi\u00e9 le nouveau <a title=\"https:\/\/www.kernel.org\/pub\/linux\/kernel\/v3.x\/linux-3.14.tar.xz\" href=\"https:\/\/www.kernel.org\/pub\/linux\/kernel\/v3.x\/linux-3.14.tar.xz\" target=\"_blank\">noyau Linux 3.14<\/a>. Ce dernier contient de nombreuses nouveaut\u00e9s, dont un m\u00e9canisme d&rsquo;<a title=\"http:\/\/en.wikipedia.org\/wiki\/Earliest_deadline_first_scheduling\" href=\"http:\/\/en.wikipedia.org\/wiki\/Earliest_deadline_first_scheduling\" target=\"_blank\">ordonnancement temps r\u00e9el EDF<\/a> (<em>Earliest Deadline First<\/em>) qu&rsquo;il me tarde d&rsquo;essayer. Pour cela deux nouveaux appels-syst\u00e8me <code>sched_getattr()<\/code> et <code>sched_setattr()<\/code> sont propos\u00e9s au programmeur, mais ils ne sont pas encore support\u00e9s par les biblioth\u00e8ques C actuelles. Qu&rsquo;\u00e0 cela ne tienne, nous allons les invoquer directement&#8230;<br \/>\n<!--more-->\n<br \/>\nBien entendu, le contenu de cet article deviendra obsol\u00e8te dans quelques semaines &#8211; ou quelques mois tout au plus &#8211; car le support de <code>sched_getattr()<\/code> et <code>sched_setattr()<\/code> sera rapidement inclus dans les mises \u00e0 jours des biblioth\u00e8ques C, mais le principe global restera valable pour de futurs appels-syst\u00e8me.<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2014\/04\/syscall.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-full wp-image-4013\" alt=\"syscall\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2014\/04\/syscall.png\" width=\"600\" height=\"412\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2014\/04\/syscall.png 600w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2014\/04\/syscall-300x206.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a>Les appels-syst\u00e8me impl\u00e9ment\u00e9s dans le noyau sont accessibles par l&rsquo;interm\u00e9diaire de fonctions d&rsquo;invocation qui se trouvent dans la biblioth\u00e8que C (par exemple GlibC). Lorsque celle-ci ignore l&rsquo;existence d&rsquo;appels-syst\u00e8me trop r\u00e9cents, il est toutefois possible de les invoquer directement par l&rsquo;interm\u00e9diaire de la fonction <code>syscall()<\/code>. Il est toutefois de notre ressort de conna\u00eetre le nombre et le type des param\u00e8tres attendus par le noyau. C&rsquo;est ce que nous allons r\u00e9aliser ci-dessous.<\/p>\n<h1>Installation du nouveau noyau<\/h1>\n<p style=\"text-align: justify;\">La premi\u00e8re \u00e9tape de cette exp\u00e9rience, consiste \u00e9videmment \u00e0 installer le nouveau noyau Linux.<\/p>\n<p style=\"text-align: justify;\">Voici pour m\u00e9moire les \u00e9tapes \u00e0 suivre sur une distribution de type Debian\/Ubuntu<\/p>\n<pre>$ <strong>wget <a title=\"http:\/\/www.kernel.org\/pub\/linux\/kernel\/v3.x\/linux-3.14.tar.xz\" href=\"http:\/\/www.kernel.org\/pub\/linux\/kernel\/v3.x\/linux-3.14.tar.xz\" target=\"_blank\">http:\/\/www.kernel.org\/pub\/linux\/kernel\/v3.x\/linux-3.14.tar.xz<\/a><\/strong>\n$ <strong>tar xJf linux-3.14.tar.xz<\/strong>\n$ <strong>cd linux-3.14<\/strong>\n$ <strong>cp \/boot\/config-<\/strong>???(le plus r\u00e9cent) <strong>.\/.config<\/strong>\n$ <strong>sudo make-kpkg --append-to-version -perso --initrd kernel_image<\/strong>\n$ <strong>cd ..<\/strong>\n$ <strong>sudo dpkg -i linux-image-3.14.0-perso*<\/strong>\n$ <strong>sudo reboot<\/strong><\/pre>\n<h1>Protoypes des appels-syst\u00e8mes consid\u00e9r\u00e9s<\/h1>\n<p style=\"text-align: justify;\">En cherchant dans les sources du noyau, nous pouvons d\u00e9terminer les prototypes des appels-syst\u00e8mes que nous souhaitons invoquer.<\/p>\n<p style=\"text-align: justify;\">Pla\u00e7ons nous dans le r\u00e9pertoire des sources, puis recherchons le premier appel-syst\u00e8me.<\/p>\n<pre>[linux-3.14]$ <strong>find . -type f | xargs grep sched_getattr<\/strong>\n.\/kernel\/sched\/core.c: * sys_sched_getattr - similar to sched_getparam, but with sched_attr\n.\/kernel\/sched\/core.c:SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,\n.\/include\/linux\/syscalls.h:asmlinkage long sys_sched_getattr(pid_t pid,\n.\/include\/uapi\/asm-generic\/unistd.h:#define __NR_sched_getattr 275\n.\/include\/uapi\/asm-generic\/unistd.h:__SYSCALL(__NR_sched_getattr, sys_sched_getattr)\n[...]<\/pre>\n<p style=\"text-align: justify;\">L&rsquo;appel est impl\u00e9ment\u00e9 dans le fichier <code>kernel\/sched\/core.c<\/code> (seconde ligne de r\u00e9sultat) par la macro <code>SYSCALL_DEFINE4<\/code>. Celle-ci indique que la fonction prendra quatre arguments.<\/p>\n<p style=\"text-align: justify;\">Le prototype est d\u00e9crit dans <code>include\/linux\/syscalls.h<\/code> dont voici un extrait.<\/p>\n<pre>asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,\n                                        struct sched_param __user *param);\nasmlinkage long sys_sched_setparam(pid_t pid,\n                                        struct sched_param __user *param);\n<strong>asmlinkage long sys_sched_setattr(pid_t pid,\n                                        struct sched_attr __user *attr,\n                                        unsigned int flags);\n<\/strong>asmlinkage long sys_sched_getscheduler(pid_t pid);\nasmlinkage long sys_sched_getparam(pid_t pid,\n                                        struct sched_param __user *param);\n<strong>asmlinkage long sys_sched_getattr(pid_t pid,\n                                        struct sched_attr __user *attr,\n                                        unsigned int size,\n                                        unsigned int flags);<\/strong><\/pre>\n<p style=\"text-align: justify;\">Nous notons la pr\u00e9sence \u00e9galement du nouvel appel-syst\u00e8me <code>sched_setattr()<\/code>. Ces deux fonctions prennent en argument un pointeur sur une structure <code>sched_attr<\/code> sp\u00e9cifiquement d\u00e9finie pour elles. Recherchons sa d\u00e9claration&#8230;<\/p>\n<pre>[linux-3.14]$ <strong>find . -name '*.h' | xargs grep sched_attr<\/strong>\n.\/include\/linux\/syscalls.h:struct sched_attr;\n.\/include\/linux\/syscalls.h:\t\t\t\t\tstruct sched_attr __user *attr,\n.\/include\/linux\/syscalls.h:\t\t\t\t\tstruct sched_attr __user *attr,\n.\/include\/linux\/sched.h: * This variant (sched_attr) is meant at describing a so-called\n.\/include\/linux\/sched.h: * This is reflected by the actual fields of the sched_attr structure:\n.\/include\/linux\/sched.h:<strong>struct sched_attr<\/strong> {\n.\/include\/linux\/sched.h:\t * Original scheduling parameters. Copied here from sched_attr\n.\/include\/linux\/sched.h:\t\t\t const struct sched_attr *);<\/pre>\n<p style=\"text-align: justify;\">Nous pouvons donc examiner cette structure dans <code>include\/linux\/sched.h<\/code>.<\/p>\n<pre>\/*\n * Extended scheduling parameters data structure.\n *\n * This is needed because the original struct sched_param can not be\n * altered without introducing ABI issues with legacy applications\n * (e.g., in sched_getparam()).\n *\n * However, the possibility of specifying more than just a priority for\n * the tasks may be useful for a wide variety of application fields, e.g.,\n * multimedia, streaming, automation and control, and many others.\n *\n * This variant (sched_attr) is meant at describing a so-called\n * sporadic time-constrained task. In such model a task is specified by:\n *  - the activation period or minimum instance inter-arrival time;\n *  - the maximum (or average, depending on the actual scheduling\n *    discipline) computation time of all instances, a.k.a. runtime;\n *  - the deadline (relative to the actual activation time) of each\n *    instance.\n * Very briefly, a periodic (sporadic) task asks for the execution of\n * some specific computation --which is typically called an instance--\n * (at most) every period. Moreover, each instance typically lasts no more\n * than the runtime and must be completed by time instant t equal to\n * the instance activation time + the deadline.\n *\n * This is reflected by the actual fields of the sched_attr structure:\n *\n *  @size               size of the structure, for fwd\/bwd compat.\n *\n *  @sched_policy       task's scheduling policy\n *  @sched_flags        for customizing the scheduler behaviour\n *  @sched_nice         task's nice value      (SCHED_NORMAL\/BATCH)\n *  @sched_priority     task's static priority (SCHED_FIFO\/RR)\n *  @sched_deadline     representative of the task's deadline\n *  @sched_runtime      representative of the task's runtime\n *  @sched_period       representative of the task's period\n *\n * Given this task model, there are a multiplicity of scheduling algorithms\n * and policies, that can be used to ensure all the tasks will make their\n * timing constraints.\n *\n * As of now, the SCHED_DEADLINE policy (sched_dl scheduling class) is the\n * only user of this new interface. More information about the algorithm\n * available in the scheduling class file or in Documentation\/.\n *\/\n<strong>struct sched_attr<\/strong> {\n        u32 size;\n\n        u32 sched_policy;\n        u64 sched_flags;\n\n        \/* SCHED_NORMAL, SCHED_BATCH *\/\n        s32 sched_nice;\n\n        \/* SCHED_FIFO, SCHED_RR *\/\n        u32 sched_priority;\n\n        \/* SCHED_DEADLINE *\/\n        u64 sched_runtime;\n        u64 sched_deadline;\n        u64 sched_period;\n};<\/pre>\n<h1>Num\u00e9rotation des appels-syst\u00e8me<\/h1>\n<p style=\"text-align: justify;\">Lorsque nous voudrons invoquer depuis un programme utilisateur ces nouveaux appels-syst\u00e8me, nous pourrons utiliser la fonction <code>syscall()<\/code> de la biblioth\u00e8que C. N\u00e9anmoins celle-ci prend en argument le num\u00e9ro de l&rsquo;appel-syst\u00e8me d\u00e9sir\u00e9, qu&rsquo;il nous faut trouver dans les sources de Linux.<\/p>\n<p style=\"text-align: justify;\">Pour compliquer cette t\u00e2che, ce num\u00e9ro d\u00e9pend de l&rsquo;architecture, et notre programme applicatif devra \u00eatre compil\u00e9 sp\u00e9cifiquement pour une cible donn\u00e9e. Les num\u00e9ros d&rsquo;appel-syst\u00e8mes sont d\u00e9clar\u00e9s dans des fichiers d&rsquo;en-t\u00eate, pr\u00e9fix\u00e9s de <code>__NR_<\/code>.<\/p>\n<pre>[linux-3.14]$ <strong>find arch  -type f | xargs grep __NR_sched_getattr<\/strong>\narch\/sparc\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t344\narch\/m68k\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t350\narch\/powerpc\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t356\narch\/ia64\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t\t1337\narch\/s390\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t346\narch\/x86\/include\/generated\/uapi\/asm\/unistd_64.h:#define __NR_sched_getattr 315\narch\/x86\/include\/generated\/uapi\/asm\/unistd_x32.h:#define __NR_sched_getattr (__X32_SYSCALL_BIT + 315)\narch\/x86\/include\/generated\/uapi\/asm\/unistd_32.h:#define __NR_sched_getattr 352\narch\/mips\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t\t(__NR_Linux + 350)\narch\/mips\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t\t(__NR_Linux + 310)\narch\/mips\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t\t(__NR_Linux + 314)\narch\/arm\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t\t(__NR_SYSCALL_BASE+381)\narch\/xtensa\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t\t\t335\narch\/parisc\/include\/uapi\/asm\/unistd.h:#define __NR_sched_getattr\t(__NR_Linux + 335)\n[linux-3.14]$ <strong>find arch  -type f | xargs grep __NR_sched_setattr<\/strong>\narch\/sparc\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t343\narch\/m68k\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t349\narch\/powerpc\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t355\narch\/ia64\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t\t1336\narch\/s390\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t345\narch\/x86\/include\/generated\/uapi\/asm\/unistd_64.h:#define __NR_sched_setattr 314\narch\/x86\/include\/generated\/uapi\/asm\/unistd_x32.h:#define __NR_sched_setattr (__X32_SYSCALL_BIT + 314)\narch\/x86\/include\/generated\/uapi\/asm\/unistd_32.h:#define __NR_sched_setattr 351\narch\/mips\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t\t(__NR_Linux + 349)\narch\/mips\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t\t(__NR_Linux + 309)\narch\/mips\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t\t(__NR_Linux + 313)\narch\/arm\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t\t(__NR_SYSCALL_BASE+380)\narch\/xtensa\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t\t\t334\narch\/parisc\/include\/uapi\/asm\/unistd.h:#define __NR_sched_setattr\t(__NR_Linux + 334)\n[linux-3.14]$<\/pre>\n<p style=\"text-align: justify;\">Nous avons donc, pour le couple <code>sched_getattr()<\/code>\/<code>sched_setattr()<\/code> les valeurs 352\/351 pour un PC x86 32 bits, 315\/314 pour un x86 64 bits, et ainsi de suite pour les autres architectures.<\/p>\n<p style=\"text-align: justify;\">Il nous manque une derni\u00e8re valeur, celle de la constante <code>SCHED_DEADLINE<\/code> utilis\u00e9e pour choisir l&rsquo;ordonnancement EDF.<\/p>\n<pre>[linux-3.14]$ find include -name '*.h' | xargs grep SCHED_DEADLINE\ninclude\/linux\/sched.h: * As of now, the SCHED_DEADLINE policy (sched_dl scheduling class) is the\ninclude\/linux\/sched.h:\t\/* SCHED_DEADLINE *\/\ninclude\/linux\/sched\/deadline.h:#ifndef _SCHED_DEADLINE_H\ninclude\/linux\/sched\/deadline.h:#define _SCHED_DEADLINE_H\ninclude\/linux\/sched\/deadline.h: * SCHED_DEADLINE tasks has negative priorities, reflecting\ninclude\/linux\/sched\/deadline.h:#endif \/* _SCHED_DEADLINE_H *\/\ninclude\/generated\/autoconf.h:#define CONFIG_IOSCHED_DEADLINE 1\ninclude\/uapi\/linux\/sched.h:<strong>#define SCHED_DEADLINE      6<\/strong><\/pre>\n<p style=\"text-align: justify;\">Il s&rsquo;agit donc de la constante <strong>6<\/strong>.<\/p>\n<h1>Impl\u00e9mentation des appels-syst\u00e8me dans un programme utilisateur<\/h1>\n<p style=\"text-align: justify;\"><strong>Attention&nbsp;!<\/strong> L&rsquo;invocation directe des appels-syst\u00e8me est une source d&rsquo;erreurs faciles, et donc potentiellement dangereuse pour votre syst\u00e8me et vos donn\u00e9es. Vous voici pr\u00e9venus \ud83d\ude09<\/p>\n<p style=\"text-align: justify;\">Nous allons impl\u00e9menter les invocations des appels-syst\u00e8me et la d\u00e9claration de la structure <code>sched_param<\/code>, en prot\u00e9geant ce code par une compilation conditionnelle sur la constante <code>SCHED_DEADLINE<\/code>. Ainsi lorsque les prochaines mises \u00e0 jour de la biblioth\u00e8que C viendront impl\u00e9menter ces fonctions, notre programme pourra continuer \u00e0 fonctionner, esp\u00e9rons-le, de mani\u00e8re transparente.<\/p>\n<p style=\"text-align: justify;\">En examinant l&rsquo;impl\u00e9mentation de ces fonctions dans le noyau, nous pouvons voir que certaines suppositions sont faites sur le contenu des champs de la structure <code>sched_attr<\/code> lorsque l&rsquo;on choisit un ordonnancement <code>SCHED_DEADLINE<\/code><\/p>\n<ul>\n<li style=\"text-align: justify;\">le champ <code>sched_priority<\/code> doit \u00eatre nul<\/li>\n<li style=\"text-align: justify;\">le champ <code>sched_flags<\/code> doit contenir la valeur <code>SCHED_FLAG_RESET_ON_FORK<\/code> (d\u00e9finie \u00e0 1). En effet, <strong>une t\u00e2che ordonnanc\u00e9e en <em>deadline<\/em> ne peut pas invoquer <code>fork()<\/code><\/strong>&#8230;<\/li>\n<li style=\"text-align: justify;\">le champ <code>sched_runtime<\/code> doit \u00eatre sup\u00e9rieur ou \u00e9gal \u00e0 1024<\/li>\n<li style=\"text-align: justify;\">le champ <code>sched_deadline<\/code> doit \u00eatre sup\u00e9rieur ou \u00e9gal \u00e0 <code>sched_runtime<\/code><\/li>\n<li style=\"text-align: justify;\">le champ <code>sched_period<\/code> doit \u00eatre nul, sinon il doit \u00eatre sup\u00e9rieur ou \u00e9gal \u00e0 <code>sched_deadline<\/code><\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Commen\u00e7ons par cr\u00e9er une petite biblioth\u00e8que contenant nos appels-syst\u00e8me.<\/p>\n<pre><strong>schedattr.c:<\/strong>\n\n#define _GNU_SOURCE\n#include &lt;sched.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;sys\/syscall.h&gt;\n\n#ifndef SCHED_DEADLINE\n\n#include &lt;schedattr.h&gt;\n\n\/\/ Definitions pour x86_64\n#define SCHED_SETATTR_SYSCALL_NB 314\n#define SCHED_GETATTR_SYSCALL_NB 315\n\n\/\/ Definitions pour i386\n\/\/#define SCHED_SETATTR_SYSCALL_NB 351\n\/\/#define SCHED_GETATTR_SYSCALL_NB 352\n\nlong <strong>sched_getattr<\/strong>(pid_t pid, struct sched_attr * attr, unsigned int size, unsigned int flags)\n{\n  return syscall(SCHED_GETATTR_SYSCALL_NB, pid, attr, size, flags);\n}\n\n#define SCHED_FLAG_RESET_ON_FORK  1\n\nlong <strong>sched_setattr<\/strong>(pid_t pid, struct sched_attr * attr, unsigned int flags)\n{\n  if (attr-&gt;sched_policy == SCHED_DEADLINE) {\n    attr-&gt;sched_priority = 0;\n    attr-&gt;sched_flags |= SCHED_FLAG_RESET_ON_FORK;\n  }\n  return <strong>syscall<\/strong>(SCHED_SETATTR_SYSCALL_NB, pid, attr, flags);\n}\n#endif<\/pre>\n<p>Lors de la compilation, d\u00e9finissez les constantes symboliques <code>SCHED_SETATTR_SYSCALL_NB<\/code> et <code>SCHED_GETATTR_SYSCALL_NB<\/code> avec les num\u00e9ros d&rsquo;appels-syst\u00e8me correspondant \u00e0 votre architecture.<\/p>\n<p>Les prototypes des fonctions et la d\u00e9claration de la structure se trouvent dans un fichier d&rsquo;en-t\u00eate.<\/p>\n<pre><strong>schedattr.h:<\/strong>\n#ifndef LIB_SCHED_ATTR\n#define LIB_SCHED_ATTR\n\n#ifndef SCHED_DEADLINE\n#define SCHED_DEADLINE  6\n\n<strong>struct sched_attr<\/strong> {\n  __uint32_t size;\n\n  __uint32_t sched_policy;\n  __uint64_t sched_flags;\n\n  \/* SCHED_OTHER *\/\n  __int32_t sched_nice;\n\n  \/* SCHED_FIFO, SCHED_RR *\/\n  __uint32_t sched_priority;\n\n  \/* SCHED_DEADLINE *\/\n  __uint64_t sched_runtime; \n  __uint64_t sched_deadline;\n  __uint64_t sched_period;\n};\n\nextern long <strong>sched_getattr<\/strong>(pid_t pid, struct sched_attr * attr, unsigned int size, unsigned int flags);\n\nextern long <strong>sched_setattr<\/strong>(pid_t pid, struct sched_attr * attr, unsigned int flags);\n\n#endif\n#endif<\/pre>\n<p>Voici un premier programme qui utilise notre biblioth\u00e8que pour lire le type d&rsquo;ordonnancement des processus indiqu\u00e9s sur sa ligne de commande.<\/p>\n<pre><strong>sched-getattr.c:<\/strong> \n\n#include &lt;sched.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;schedattr.h&gt;\n#include &lt;unistd.h&gt;\n\nint main(int argc, char * argv [])\n{\n  int i;\n  int pid;\n  struct sched_attr attr;\n\n  for (i = 1; i &lt; argc; i ++) {\n    if (sscanf(argv[i], \"%d\", &amp; pid) != 1) {\n      fprintf(stderr, \"usage: %s pid...\\n\", argv[0]);\n      exit(EXIT_FAILURE);\n    }\n    if (<strong>sched_getattr<\/strong>(pid, &amp; attr, sizeof(struct sched_attr), 0) != 0) {\n      perror(argv[i]);\n      continue;\n    }\n    printf(\"%d: \", pid);\n    if (attr.sched_policy == SCHED_FIFO) {\n      printf(\"Realtime FIFO scheduling, priority=%d\\n\", attr.sched_priority);\n      continue;\n    }\n    if (attr.sched_policy == SCHED_RR) {\n      printf(\"Realtime RR scheduling, priority=%d\\n\", attr.sched_priority);\n      continue;\n    }\n    if (attr.sched_policy == SCHED_DEADLINE) {\n      printf(\"Deadline scheduling, runtime=%lu, deadline=%lu, period=%lu\\n\",\n             attr.sched_runtime, attr.sched_deadline, attr.sched_period);\n      continue;\n    }\n    printf(\"Timesharing scheduling, nice=%d\\n\", attr.sched_nice);\n  }\n  return EXIT_SUCCESS;\n}<\/pre>\n<p style=\"text-align: justify;\">Et un second programme qui permet de modifier enti\u00e8rement l&rsquo;ordonnancement de n&rsquo;importe quel processus existant (un peu \u00e0 la mani\u00e8re de la commande <code>chrt<\/code>).<\/p>\n<pre><strong>sched-setattr.c:<\/strong>\n\n#include &lt;sched.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;&lt;string.h&gt;\n#include &lt;&lt;schedattr.h&gt;\n#include &lt;unistd.h&gt;\n\nvoid usage_exit(const char * name)\n{\n  fprintf(stderr, \"usage: %s R &lt;priority&gt; &lt;pid&gt;        (RR)\\n\", name);\n  fprintf(stderr, \"          F &lt;priority&gt; &lt;pid&gt;        (Fifo)\\n\");\n  fprintf(stderr, \"          D &lt;Runtime&gt; &lt;dealine&gt; &lt;period&gt; &lt;pid&gt;\\n\");\n  fprintf(stderr, \"          O &lt;nice&gt; &lt;pid&gt;            (Other)\\n\");\n  exit(EXIT_FAILURE);\n}\n\nint main(int argc, char * argv [])\n{\n  int i;\n  int pid;\n  struct sched_attr attr;\n\n  i = 0;\n  while (++i &lt; argc) {\n\n    memset(&amp; attr, 0, sizeof(attr));\n\n    if (strcmp(argv[i], \"R\") == 0) {\n      attr.sched_policy = SCHED_RR;\n      if (++i == argc) {\n        fprintf(stderr, \"missing priority...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (sscanf(argv[i], \"%d\", &amp; (attr.sched_priority)) != 1) {\n        fprintf(stderr, \"wrong priority...\\n\");\n        usage_exit(argv[0]);\n      }\n    } else if (strcmp(argv[i], \"F\") == 0) {\n      attr.sched_policy = SCHED_FIFO;\n      if (++i == argc) {\n        fprintf(stderr, \"missing priority...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (sscanf(argv[i], \"%d\", &amp; (attr.sched_priority)) != 1) {\n        fprintf(stderr, \"wrong priority...\\n\");\n        usage_exit(argv[0]);\n      }\n    } else if (strcmp(argv[i], \"O\") == 0) {\n      attr.sched_policy = SCHED_OTHER;\n      if (++i == argc) {\n        fprintf(stderr, \"missing nice value...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (sscanf(argv[i], \"%d\", &amp; (attr.sched_nice)) != 1) {\n        fprintf(stderr, \"wrong nice value...\\n\");\n        usage_exit(argv[0]);\n      }\n    } else if (strcmp(argv[i], \"D\") == 0) {\n      attr.sched_policy = SCHED_DEADLINE;\n      if (++i == argc) {\n        fprintf(stderr, \"missing runtime value...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (sscanf(argv[i], \"%lu\", &amp; (attr.sched_runtime)) != 1) {\n        fprintf(stderr, \"wrong runtime value...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (++i == argc) {\n        fprintf(stderr, \"missing deadline value...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (sscanf(argv[i], \"%lu\", &amp; (attr.sched_deadline)) != 1) {\n        fprintf(stderr, \"wrong deadline value...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (++i == argc) {\n        fprintf(stderr, \"missing period value...\\n\");\n        usage_exit(argv[0]);\n      }\n      if (sscanf(argv[i], \"%lu\", &amp; (attr.sched_period)) != 1) {\n        fprintf(stderr, \"wrong period value...\\n\");\n        usage_exit(argv[0]);\n      }\n    } else {\n      fprintf(stderr, \"unknown %s scheduling...\\n\", argv[i]);\n      usage_exit(argv[0]);\n    }\n\n    if (++i == argc) {\n      fprintf(stderr, \"missing pid...\\n\");\n      usage_exit(argv[0]);\n    }\n    if (sscanf(argv[i], \"%d\", &amp; pid) != 1) {\n      fprintf(stderr, \"wrong pid...\\n\");\n      usage_exit(argv[0]);\n    }\n    if (<strong>sched_setattr<\/strong>(pid, &amp; attr, 0) != 0) {\n      perror(argv[i]);\n    }\n  }\n\n  return EXIT_SUCCESS;\n}<\/pre>\n<p style=\"text-align: justify;\">Pour finir, voici le fichier Makefile permettant de tout compiler.<\/p>\n<pre><strong>Makefile:<\/strong>\n\nCC=${CROSS_COMPILE}gcc\n\n.PHONY: all\n\nall: libschedattr.so.1.0 sched-getattr sched-setattr\n\nlibschedattr.so.1.0: libschedattr.so\n  ln -sf libschedattr.so libschedattr.so.1\n  ln -sf libschedattr.so.1 libschedattr.so.1.0\n\nlibschedattr.so: schedattr.o\n  ${CC} -shared -Wl,-soname,libschedattr.so.1.0 schedattr.o -o libschedattr.so\n\nschedattr.o: schedattr.c\n  ${CC} -c -fPIC -Wall schedattr.c -I.\n\nsched-getattr: sched-getattr.c libschedattr.so.1.0\n  ${CC} -Wall -I. -L. -o sched-getattr sched-getattr.c -lschedattr\n\nsched-setattr: sched-setattr.c libschedattr.so.1.0\n  ${CC} -Wall -I. -L. -o sched-setattr sched-setattr.c -lschedattr\n\n.PHONY: clean\n\nclean:\n  rm -f schedattr.o libschedattr*\n  rm -f sched-getattr\n  rm -f sched-setattr<\/pre>\n<p style=\"text-align: justify;\">Vous trouverez l&rsquo;ensemble de tous ces fichiers dans <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2014-04-05\/schedattr.tar.bz2\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2014-04-05\/schedattr.tar.bz2\"><strong>cette archive<\/strong><\/a>.<\/p>\n<h1>Utilisation<\/h1>\n<p style=\"text-align: justify;\">Apr\u00e8s compilation, nous trouvons dans notre r\u00e9pertoire le fichier de la biblioth\u00e8que (libschedattr.so.1.0), deux liens symboliques permettant d&rsquo;y acc\u00e9der, et deux fichiers ex\u00e9cutables.<\/p>\n<pre>[~]$ <strong>tar xjf schedattr.tar.bz2 <\/strong>\n[~]$ <strong>cd schedattr\/<\/strong>\n[schedattr]$ <strong>make<\/strong>\ngcc -c -fPIC -Wall schedattr.c -I.\ngcc -shared -Wl,-soname,libschedattr.so.1.0 schedattr.o -o libschedattr.so\nln -sf libschedattr.so libschedattr.so.1\nln -sf libschedattr.so.1 libschedattr.so.1.0\ngcc -Wall -I. -L. -o sched-getattr sched-getattr.c -lschedattr\ngcc -Wall -I. -L. -o sched-setattr sched-setattr.c -lschedattr\n[schedattr]$ <strong>ls -l<\/strong>\ntotal 60\n-rwxrwxr-x 1 cpb cpb  7960 avril  5 06:27 libschedattr.so\nlrwxrwxrwx 1 cpb cpb    15 avril  5 06:27 libschedattr.so.1 -&gt; libschedattr.so\nlrwxrwxrwx 1 cpb cpb    17 avril  5 06:27 libschedattr.so.1.0 -&gt; libschedattr.so.1\n-rw-rw-r-- 1 cpb cpb   726 avril  5 06:11 Makefile\n-rw-rw-r-- 1 cpb cpb  1685 avril  5 06:14 schedattr.c\n-rw-rw-r-- 1 cpb cpb  1465 avril  5 06:16 schedattr.h\n-rw-rw-r-- 1 cpb cpb  1664 avril  5 06:27 schedattr.o\n-rwxrwxr-x 1 cpb cpb  8873 avril  5 06:27 sched-getattr\n-rw-rw-r-- 1 cpb cpb  1892 avril  5 06:16 sched-getattr.c\n-rwxrwxr-x 1 cpb cpb 13108 avril  5 06:27 sched-setattr\n-rw-rw-r-- 1 cpb cpb  3604 avril  5 06:16 sched-setattr.c\n[schedattr]$<\/pre>\n<p style=\"text-align: justify;\">Pour que les programmes puissent fonctionner, il faut qu&rsquo;ils soient capables de trouver la biblioth\u00e8que. Deux possibilit\u00e9s&nbsp;:<\/p>\n<ul>\n<li style=\"text-align: justify;\">vous copiez le fichier <code>libschedattr.so.1.0<\/code> dans <code>\/usr\/local\/lib<\/code> par exemple puis lancez la commande <code>ldconfig<\/code> pour que les liens n\u00e9cessaires y soient cr\u00e9\u00e9s.<\/li>\n<li style=\"text-align: justify;\">vous remplissez la variable d&rsquo;environnement <code>LD_LIBRARY_PATH<\/code> avec le r\u00e9pertoire contenant la biblioth\u00e8que (ou le point pour repr\u00e9senter le r\u00e9pertoire courant) avant de lancer les commandes<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">C&rsquo;est la seconde solution que je vais adopter.<\/p>\n<h2><code>sched-getattr<\/code><\/h2>\n<p style=\"text-align: justify;\">Commen\u00e7ons par v\u00e9rifier le comportement de <code>sched-getattr<\/code>. La variable <code>$$<\/code> contient toujours le PID du shell courant.<\/p>\n<pre>[schedattr]$ <strong>export LD_LIBRARY_PATH=.<\/strong>\n[schedattr]$ <strong>echo $$<\/strong>\n16337\n[schedattr]$ <strong>.\/sched-getattr 16337<\/strong>\n16337: Timesharing scheduling, nice=0<\/pre>\n<p style=\"text-align: justify;\">Le shell est ordonnanc\u00e9 en temps partag\u00e9 avec une valeur de nice nulle, c&rsquo;est normal. Modifions cette valeur.<\/p>\n<pre>[schedattr]$ <strong>renice -n +5 16337<\/strong>\n16337 (process ID) old priority 0, new priority 5\n[schedattr]$ <strong>.\/sched-getattr 16337<\/strong>\n16337: Timesharing scheduling, nice=5<\/pre>\n<p style=\"text-align: justify;\">Notre programme a vu la modification, l&rsquo;appel-syst\u00e8me <code>sched_getattr()<\/code> semble fonctionner. Passons le shell en temps r\u00e9el avec la commande <code>chrt<\/code> et v\u00e9rifions ce qu&rsquo;indique <code>sched-getattr<\/code>.<\/p>\n<pre>[schedattr]$ <strong>sudo chrt -pf 20 16337<\/strong>\n[schedattr]$ <strong>.\/sched-getattr 16337<\/strong>\n16337: Realtime FIFO scheduling, priority=20<\/pre>\n<p style=\"text-align: justify;\">Parfait. V\u00e9rifions pour l&rsquo;ordonnancement <em>Round Robin<\/em>.<\/p>\n<pre>[schedattr]$ <strong>sudo chrt -pr 40 16337<\/strong>\n[schedattr]$ <strong>.\/sched-getattr 16337<\/strong>\n16337: Realtime RR scheduling, priority=40\n[schedattr]$<\/pre>\n<h2><code>sched-setattr<\/code><\/h2>\n<p style=\"text-align: justify;\">Nous allons maintenant v\u00e9rifier le fonctionnement du programme <code>sched-setattr<\/code>. Commen\u00e7ons par les ordonnancements temps partag\u00e9, temps r\u00e9el <em>Fifo<\/em> et <em>Round Robin<\/em> en v\u00e9rifiant le r\u00e9sultat du changement d&rsquo;ordonnancement avec <code>chrt<\/code>.<\/p>\n<pre>[schedattr]$ <strong>.\/sched-setattr --help<\/strong>\nunknown --help scheduling...\nusage: .\/sched-setattr R &lt;priority&gt; &lt;pid&gt;        (RR)\n          F &lt;priority&gt; &lt;pid&gt;        (Fifo)\n          D &lt;Runtime&gt; &lt;Dealine&gt; &lt;Period&gt; &lt;pid&gt;\n          O &lt;nice&gt; &lt;pid&gt;            (Other)\n[schedattr]$ <strong>sudo LD_LIBRARY_PATH=.   .\/sched-setattr O 0 16337<\/strong>\n[schedattr]$ <strong>chrt -p 16337<\/strong>\npid 16337's current scheduling policy: SCHED_OTHER\npid 16337's current scheduling priority: 0\n[schedattr]$ <strong>sudo LD_LIBRARY_PATH=.   .\/sched-setattr R 10 16337<\/strong>\n[schedattr]$ <strong>chrt -p 16337<\/strong>\npid 16337's current scheduling policy: SCHED_RR\npid 16337's current scheduling priority: 10\n[schedattr]$ <strong>sudo LD_LIBRARY_PATH=.   .\/sched-setattr F 20 16337<\/strong>\n[schedattr]$ <strong>chrt -p 16337<\/strong>\npid 16337's current scheduling policy: SCHED_FIFO\npid 16337's current scheduling priority: 20<\/pre>\n<p style=\"text-align: justify; padding-left: 30px;\">Notez la syntaxe permettant d&rsquo;initialiser une variable d&rsquo;environnement sp\u00e9cialement pour ex\u00e9cuter la commande se trouvant sur le reste de la ligne. Ceci est n\u00e9cessaire \u00e0 cause du <code>sudo<\/code> qui efface l&rsquo;environnement avant de lancer la commande qu&rsquo;on lui transmet.<\/p>\n<p style=\"text-align: justify;\">Passons en ordonnancement <em>deadline<\/em> et v\u00e9rifions avec <code>chrt<\/code>.<\/p>\n<pre>[schedattr]$ <strong>sudo LD_LIBRARY_PATH=.   .\/sched-setattr D 1024 2048 4096 16337<\/strong>\n[schedattr]$ <strong>chrt -p 16337<\/strong>\nchrt: unknown scheduling policy\nchrt: \u00e9chec d'obtention des attributs du PID\u00a016337: Argument invalide\npid 16337's current scheduling policy: [schedattr]$<\/pre>\n<p style=\"text-align: justify;\">H\u00e9 oui&nbsp;! La commande <code>chrt<\/code> ne conna\u00eet pas encore ce type d&rsquo;ordonnancement. Elle \u00e9choue donc (et se plante un peu maladroitement&#8230;) en essayant d&rsquo;interpr\u00e9ter les r\u00e9sultats obtenus avec l&rsquo;ancien appel <code>sched_getschedparam()<\/code>, le seul appel-syst\u00e8me qu&rsquo;elle connaisse. Mais nous pouvons v\u00e9rifier le comportement avec <code>sched_getattr()<\/code>:<\/p>\n<pre>[schedattr]$ <strong>.\/sched-getattr 16337<\/strong>\n16337: Deadline scheduling, runtime=1024, deadline=2048, period=4096\n[schedattr]$<\/pre>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Le but de cet article est d&rsquo;utiliser des appels-syst\u00e8me nouveaux, inconnus de la biblioth\u00e8que C. Ce que l&rsquo;on a vu ci-dessus pourrait s&rsquo;appliquer \u00e0 d&rsquo;autres circonstances&nbsp;: invocation d&rsquo;un appel-syst\u00e8me personnalis\u00e9, utilisation d&rsquo;une biblioth\u00e8que C ancienne sur un noyau r\u00e9cent, etc.<\/p>\n<p style=\"text-align: justify;\">Nous avons obtenu deux programmes qui nous donnent acc\u00e8s au m\u00e9canisme d&rsquo;ordonnancement temps r\u00e9el <em>deadline<\/em> apparu dans le noyau 3.14. Il nous reste \u00e0 comprendre comment fonctionne cet ordonnancement&#8230; Ce qui fera l&rsquo;objet d&rsquo;un prochain article.<\/p>","protected":false},"excerpt":{"rendered":"<p>Lundi dernier, Linus a publi&eacute; le nouveau noyau Linux 3.14. Ce dernier contient de nombreuses nouveaut&eacute;s, dont un m&eacute;canisme d&rsquo;ordonnancement temps r&eacute;el EDF (Earliest Deadline First) qu&rsquo;il me tarde d&rsquo;essayer. Pour cela deux nouveaux appels-syst&egrave;me sched_getattr() et sched_setattr() sont propos&eacute;s au programmeur, mais ils ne sont pas encore support&eacute;s par les biblioth&egrave;ques C actuelles. Qu&rsquo;&agrave; [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,8],"tags":[],"class_list":["post-3998","post","type-post","status-publish","format-standard","hentry","category-actualite","category-linux-2"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3998","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=3998"}],"version-history":[{"count":16,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3998\/revisions"}],"predecessor-version":[{"id":4023,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3998\/revisions\/4023"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=3998"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=3998"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=3998"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}