Lundi dernier, Linus a publié le nouveau noyau Linux 3.14. Ce dernier contient de nombreuses nouveautés, dont un mécanisme d’ordonnancement temps réel EDF (Earliest Deadline First) qu’il me tarde d’essayer. Pour cela deux nouveaux appels-système sched_getattr()
et sched_setattr()
sont proposés au programmeur, mais ils ne sont pas encore supportés par les bibliothèques C actuelles. Qu’à cela ne tienne, nous allons les invoquer directement…
Bien entendu, le contenu de cet article deviendra obsolète dans quelques semaines – ou quelques mois tout au plus – car le support de sched_getattr()
et sched_setattr()
sera rapidement inclus dans les mises à jours des bibliothèques C, mais le principe global restera valable pour de futurs appels-système.
Les appels-système implémentés dans le noyau sont accessibles par l’intermédiaire de fonctions d’invocation qui se trouvent dans la bibliothèque C (par exemple GlibC). Lorsque celle-ci ignore l’existence d’appels-système trop récents, il est toutefois possible de les invoquer directement par l’intermédiaire de la fonction syscall()
. Il est toutefois de notre ressort de connaître le nombre et le type des paramètres attendus par le noyau. C’est ce que nous allons réaliser ci-dessous.
Installation du nouveau noyau
La première étape de cette expérience, consiste évidemment à installer le nouveau noyau Linux.
Voici pour mémoire les étapes à suivre sur une distribution de type Debian/Ubuntu
$ wget http://www.kernel.org/pub/linux/kernel/v3.x/linux-3.14.tar.xz $ tar xJf linux-3.14.tar.xz $ cd linux-3.14 $ cp /boot/config-???(le plus récent) ./.config $ sudo make-kpkg --append-to-version -perso --initrd kernel_image $ cd .. $ sudo dpkg -i linux-image-3.14.0-perso* $ sudo reboot
Protoypes des appels-systèmes considérés
En cherchant dans les sources du noyau, nous pouvons déterminer les prototypes des appels-systèmes que nous souhaitons invoquer.
Plaçons nous dans le répertoire des sources, puis recherchons le premier appel-système.
[linux-3.14]$ find . -type f | xargs grep sched_getattr ./kernel/sched/core.c: * sys_sched_getattr - similar to sched_getparam, but with sched_attr ./kernel/sched/core.c:SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, ./include/linux/syscalls.h:asmlinkage long sys_sched_getattr(pid_t pid, ./include/uapi/asm-generic/unistd.h:#define __NR_sched_getattr 275 ./include/uapi/asm-generic/unistd.h:__SYSCALL(__NR_sched_getattr, sys_sched_getattr) [...]
L’appel est implémenté dans le fichier kernel/sched/core.c
(seconde ligne de résultat) par la macro SYSCALL_DEFINE4
. Celle-ci indique que la fonction prendra quatre arguments.
Le prototype est décrit dans include/linux/syscalls.h
dont voici un extrait.
asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param); asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param); asmlinkage long sys_sched_setattr(pid_t pid, struct sched_attr __user *attr, unsigned int flags); asmlinkage long sys_sched_getscheduler(pid_t pid); asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param); asmlinkage long sys_sched_getattr(pid_t pid, struct sched_attr __user *attr, unsigned int size, unsigned int flags);
Nous notons la présence également du nouvel appel-système sched_setattr()
. Ces deux fonctions prennent en argument un pointeur sur une structure sched_attr
spécifiquement définie pour elles. Recherchons sa déclaration…
[linux-3.14]$ find . -name '*.h' | xargs grep sched_attr ./include/linux/syscalls.h:struct sched_attr; ./include/linux/syscalls.h: struct sched_attr __user *attr, ./include/linux/syscalls.h: struct sched_attr __user *attr, ./include/linux/sched.h: * This variant (sched_attr) is meant at describing a so-called ./include/linux/sched.h: * This is reflected by the actual fields of the sched_attr structure: ./include/linux/sched.h:struct sched_attr { ./include/linux/sched.h: * Original scheduling parameters. Copied here from sched_attr ./include/linux/sched.h: const struct sched_attr *);
Nous pouvons donc examiner cette structure dans include/linux/sched.h
.
/* * Extended scheduling parameters data structure. * * This is needed because the original struct sched_param can not be * altered without introducing ABI issues with legacy applications * (e.g., in sched_getparam()). * * However, the possibility of specifying more than just a priority for * the tasks may be useful for a wide variety of application fields, e.g., * multimedia, streaming, automation and control, and many others. * * This variant (sched_attr) is meant at describing a so-called * sporadic time-constrained task. In such model a task is specified by: * - the activation period or minimum instance inter-arrival time; * - the maximum (or average, depending on the actual scheduling * discipline) computation time of all instances, a.k.a. runtime; * - the deadline (relative to the actual activation time) of each * instance. * Very briefly, a periodic (sporadic) task asks for the execution of * some specific computation --which is typically called an instance-- * (at most) every period. Moreover, each instance typically lasts no more * than the runtime and must be completed by time instant t equal to * the instance activation time + the deadline. * * This is reflected by the actual fields of the sched_attr structure: * * @size size of the structure, for fwd/bwd compat. * * @sched_policy task's scheduling policy * @sched_flags for customizing the scheduler behaviour * @sched_nice task's nice value (SCHED_NORMAL/BATCH) * @sched_priority task's static priority (SCHED_FIFO/RR) * @sched_deadline representative of the task's deadline * @sched_runtime representative of the task's runtime * @sched_period representative of the task's period * * Given this task model, there are a multiplicity of scheduling algorithms * and policies, that can be used to ensure all the tasks will make their * timing constraints. * * As of now, the SCHED_DEADLINE policy (sched_dl scheduling class) is the * only user of this new interface. More information about the algorithm * available in the scheduling class file or in Documentation/. */ struct sched_attr { u32 size; u32 sched_policy; u64 sched_flags; /* SCHED_NORMAL, SCHED_BATCH */ s32 sched_nice; /* SCHED_FIFO, SCHED_RR */ u32 sched_priority; /* SCHED_DEADLINE */ u64 sched_runtime; u64 sched_deadline; u64 sched_period; };
Numérotation des appels-système
Lorsque nous voudrons invoquer depuis un programme utilisateur ces nouveaux appels-système, nous pourrons utiliser la fonction syscall()
de la bibliothèque C. Néanmoins celle-ci prend en argument le numéro de l’appel-système désiré, qu’il nous faut trouver dans les sources de Linux.
Pour compliquer cette tâche, ce numéro dépend de l’architecture, et notre programme applicatif devra être compilé spécifiquement pour une cible donnée. Les numéros d’appel-systèmes sont déclarés dans des fichiers d’en-tête, préfixés de __NR_
.
[linux-3.14]$ find arch -type f | xargs grep __NR_sched_getattr arch/sparc/include/uapi/asm/unistd.h:#define __NR_sched_getattr 344 arch/m68k/include/uapi/asm/unistd.h:#define __NR_sched_getattr 350 arch/powerpc/include/uapi/asm/unistd.h:#define __NR_sched_getattr 356 arch/ia64/include/uapi/asm/unistd.h:#define __NR_sched_getattr 1337 arch/s390/include/uapi/asm/unistd.h:#define __NR_sched_getattr 346 arch/x86/include/generated/uapi/asm/unistd_64.h:#define __NR_sched_getattr 315 arch/x86/include/generated/uapi/asm/unistd_x32.h:#define __NR_sched_getattr (__X32_SYSCALL_BIT + 315) arch/x86/include/generated/uapi/asm/unistd_32.h:#define __NR_sched_getattr 352 arch/mips/include/uapi/asm/unistd.h:#define __NR_sched_getattr (__NR_Linux + 350) arch/mips/include/uapi/asm/unistd.h:#define __NR_sched_getattr (__NR_Linux + 310) arch/mips/include/uapi/asm/unistd.h:#define __NR_sched_getattr (__NR_Linux + 314) arch/arm/include/uapi/asm/unistd.h:#define __NR_sched_getattr (__NR_SYSCALL_BASE+381) arch/xtensa/include/uapi/asm/unistd.h:#define __NR_sched_getattr 335 arch/parisc/include/uapi/asm/unistd.h:#define __NR_sched_getattr (__NR_Linux + 335) [linux-3.14]$ find arch -type f | xargs grep __NR_sched_setattr arch/sparc/include/uapi/asm/unistd.h:#define __NR_sched_setattr 343 arch/m68k/include/uapi/asm/unistd.h:#define __NR_sched_setattr 349 arch/powerpc/include/uapi/asm/unistd.h:#define __NR_sched_setattr 355 arch/ia64/include/uapi/asm/unistd.h:#define __NR_sched_setattr 1336 arch/s390/include/uapi/asm/unistd.h:#define __NR_sched_setattr 345 arch/x86/include/generated/uapi/asm/unistd_64.h:#define __NR_sched_setattr 314 arch/x86/include/generated/uapi/asm/unistd_x32.h:#define __NR_sched_setattr (__X32_SYSCALL_BIT + 314) arch/x86/include/generated/uapi/asm/unistd_32.h:#define __NR_sched_setattr 351 arch/mips/include/uapi/asm/unistd.h:#define __NR_sched_setattr (__NR_Linux + 349) arch/mips/include/uapi/asm/unistd.h:#define __NR_sched_setattr (__NR_Linux + 309) arch/mips/include/uapi/asm/unistd.h:#define __NR_sched_setattr (__NR_Linux + 313) arch/arm/include/uapi/asm/unistd.h:#define __NR_sched_setattr (__NR_SYSCALL_BASE+380) arch/xtensa/include/uapi/asm/unistd.h:#define __NR_sched_setattr 334 arch/parisc/include/uapi/asm/unistd.h:#define __NR_sched_setattr (__NR_Linux + 334) [linux-3.14]$
Nous avons donc, pour le couple sched_getattr()
/sched_setattr()
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.
Il nous manque une dernière valeur, celle de la constante SCHED_DEADLINE
utilisée pour choisir l’ordonnancement EDF.
[linux-3.14]$ find include -name '*.h' | xargs grep SCHED_DEADLINE include/linux/sched.h: * As of now, the SCHED_DEADLINE policy (sched_dl scheduling class) is the include/linux/sched.h: /* SCHED_DEADLINE */ include/linux/sched/deadline.h:#ifndef _SCHED_DEADLINE_H include/linux/sched/deadline.h:#define _SCHED_DEADLINE_H include/linux/sched/deadline.h: * SCHED_DEADLINE tasks has negative priorities, reflecting include/linux/sched/deadline.h:#endif /* _SCHED_DEADLINE_H */ include/generated/autoconf.h:#define CONFIG_IOSCHED_DEADLINE 1 include/uapi/linux/sched.h:#define SCHED_DEADLINE 6
Il s’agit donc de la constante 6.
Implémentation des appels-système dans un programme utilisateur
Attention ! L’invocation directe des appels-système est une source d’erreurs faciles, et donc potentiellement dangereuse pour votre système et vos données. Vous voici prévenus 😉
Nous allons implémenter les invocations des appels-système et la déclaration de la structure sched_param
, en protégeant ce code par une compilation conditionnelle sur la constante SCHED_DEADLINE
. Ainsi lorsque les prochaines mises à jour de la bibliothèque C viendront implémenter ces fonctions, notre programme pourra continuer à fonctionner, espérons-le, de manière transparente.
En examinant l’implémentation de ces fonctions dans le noyau, nous pouvons voir que certaines suppositions sont faites sur le contenu des champs de la structure sched_attr
lorsque l’on choisit un ordonnancement SCHED_DEADLINE
- le champ
sched_priority
doit être nul - le champ
sched_flags
doit contenir la valeurSCHED_FLAG_RESET_ON_FORK
(définie à 1). En effet, une tâche ordonnancée en deadline ne peut pas invoquerfork()
… - le champ
sched_runtime
doit être supérieur ou égal à 1024 - le champ
sched_deadline
doit être supérieur ou égal àsched_runtime
- le champ
sched_period
doit être nul, sinon il doit être supérieur ou égal àsched_deadline
Commençons par créer une petite bibliothèque contenant nos appels-système.
schedattr.c: #define _GNU_SOURCE #include <sched.h> #include <unistd.h> #include <sys/syscall.h> #ifndef SCHED_DEADLINE #include <schedattr.h> // Definitions pour x86_64 #define SCHED_SETATTR_SYSCALL_NB 314 #define SCHED_GETATTR_SYSCALL_NB 315 // Definitions pour i386 //#define SCHED_SETATTR_SYSCALL_NB 351 //#define SCHED_GETATTR_SYSCALL_NB 352 long sched_getattr(pid_t pid, struct sched_attr * attr, unsigned int size, unsigned int flags) { return syscall(SCHED_GETATTR_SYSCALL_NB, pid, attr, size, flags); } #define SCHED_FLAG_RESET_ON_FORK 1 long sched_setattr(pid_t pid, struct sched_attr * attr, unsigned int flags) { if (attr->sched_policy == SCHED_DEADLINE) { attr->sched_priority = 0; attr->sched_flags |= SCHED_FLAG_RESET_ON_FORK; } return syscall(SCHED_SETATTR_SYSCALL_NB, pid, attr, flags); } #endif
Lors de la compilation, définissez les constantes symboliques SCHED_SETATTR_SYSCALL_NB
et SCHED_GETATTR_SYSCALL_NB
avec les numéros d’appels-système correspondant à votre architecture.
Les prototypes des fonctions et la déclaration de la structure se trouvent dans un fichier d’en-tête.
schedattr.h: #ifndef LIB_SCHED_ATTR #define LIB_SCHED_ATTR #ifndef SCHED_DEADLINE #define SCHED_DEADLINE 6 struct sched_attr { __uint32_t size; __uint32_t sched_policy; __uint64_t sched_flags; /* SCHED_OTHER */ __int32_t sched_nice; /* SCHED_FIFO, SCHED_RR */ __uint32_t sched_priority; /* SCHED_DEADLINE */ __uint64_t sched_runtime; __uint64_t sched_deadline; __uint64_t sched_period; }; extern long sched_getattr(pid_t pid, struct sched_attr * attr, unsigned int size, unsigned int flags); extern long sched_setattr(pid_t pid, struct sched_attr * attr, unsigned int flags); #endif #endif
Voici un premier programme qui utilise notre bibliothèque pour lire le type d’ordonnancement des processus indiqués sur sa ligne de commande.
sched-getattr.c: #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <schedattr.h> #include <unistd.h> int main(int argc, char * argv []) { int i; int pid; struct sched_attr attr; for (i = 1; i < argc; i ++) { if (sscanf(argv[i], "%d", & pid) != 1) { fprintf(stderr, "usage: %s pid...\n", argv[0]); exit(EXIT_FAILURE); } if (sched_getattr(pid, & attr, sizeof(struct sched_attr), 0) != 0) { perror(argv[i]); continue; } printf("%d: ", pid); if (attr.sched_policy == SCHED_FIFO) { printf("Realtime FIFO scheduling, priority=%d\n", attr.sched_priority); continue; } if (attr.sched_policy == SCHED_RR) { printf("Realtime RR scheduling, priority=%d\n", attr.sched_priority); continue; } if (attr.sched_policy == SCHED_DEADLINE) { printf("Deadline scheduling, runtime=%lu, deadline=%lu, period=%lu\n", attr.sched_runtime, attr.sched_deadline, attr.sched_period); continue; } printf("Timesharing scheduling, nice=%d\n", attr.sched_nice); } return EXIT_SUCCESS; }
Et un second programme qui permet de modifier entièrement l’ordonnancement de n’importe quel processus existant (un peu à la manière de la commande chrt
).
sched-setattr.c: #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <<string.h> #include <<schedattr.h> #include <unistd.h> void usage_exit(const char * name) { fprintf(stderr, "usage: %s R <priority> <pid> (RR)\n", name); fprintf(stderr, " F <priority> <pid> (Fifo)\n"); fprintf(stderr, " D <Runtime> <dealine> <period> <pid>\n"); fprintf(stderr, " O <nice> <pid> (Other)\n"); exit(EXIT_FAILURE); } int main(int argc, char * argv []) { int i; int pid; struct sched_attr attr; i = 0; while (++i < argc) { memset(& attr, 0, sizeof(attr)); if (strcmp(argv[i], "R") == 0) { attr.sched_policy = SCHED_RR; if (++i == argc) { fprintf(stderr, "missing priority...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%d", & (attr.sched_priority)) != 1) { fprintf(stderr, "wrong priority...\n"); usage_exit(argv[0]); } } else if (strcmp(argv[i], "F") == 0) { attr.sched_policy = SCHED_FIFO; if (++i == argc) { fprintf(stderr, "missing priority...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%d", & (attr.sched_priority)) != 1) { fprintf(stderr, "wrong priority...\n"); usage_exit(argv[0]); } } else if (strcmp(argv[i], "O") == 0) { attr.sched_policy = SCHED_OTHER; if (++i == argc) { fprintf(stderr, "missing nice value...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%d", & (attr.sched_nice)) != 1) { fprintf(stderr, "wrong nice value...\n"); usage_exit(argv[0]); } } else if (strcmp(argv[i], "D") == 0) { attr.sched_policy = SCHED_DEADLINE; if (++i == argc) { fprintf(stderr, "missing runtime value...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%lu", & (attr.sched_runtime)) != 1) { fprintf(stderr, "wrong runtime value...\n"); usage_exit(argv[0]); } if (++i == argc) { fprintf(stderr, "missing deadline value...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%lu", & (attr.sched_deadline)) != 1) { fprintf(stderr, "wrong deadline value...\n"); usage_exit(argv[0]); } if (++i == argc) { fprintf(stderr, "missing period value...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%lu", & (attr.sched_period)) != 1) { fprintf(stderr, "wrong period value...\n"); usage_exit(argv[0]); } } else { fprintf(stderr, "unknown %s scheduling...\n", argv[i]); usage_exit(argv[0]); } if (++i == argc) { fprintf(stderr, "missing pid...\n"); usage_exit(argv[0]); } if (sscanf(argv[i], "%d", & pid) != 1) { fprintf(stderr, "wrong pid...\n"); usage_exit(argv[0]); } if (sched_setattr(pid, & attr, 0) != 0) { perror(argv[i]); } } return EXIT_SUCCESS; }
Pour finir, voici le fichier Makefile permettant de tout compiler.
Makefile: CC=${CROSS_COMPILE}gcc .PHONY: all all: libschedattr.so.1.0 sched-getattr sched-setattr libschedattr.so.1.0: libschedattr.so ln -sf libschedattr.so libschedattr.so.1 ln -sf libschedattr.so.1 libschedattr.so.1.0 libschedattr.so: schedattr.o ${CC} -shared -Wl,-soname,libschedattr.so.1.0 schedattr.o -o libschedattr.so schedattr.o: schedattr.c ${CC} -c -fPIC -Wall schedattr.c -I. sched-getattr: sched-getattr.c libschedattr.so.1.0 ${CC} -Wall -I. -L. -o sched-getattr sched-getattr.c -lschedattr sched-setattr: sched-setattr.c libschedattr.so.1.0 ${CC} -Wall -I. -L. -o sched-setattr sched-setattr.c -lschedattr .PHONY: clean clean: rm -f schedattr.o libschedattr* rm -f sched-getattr rm -f sched-setattr
Vous trouverez l’ensemble de tous ces fichiers dans cette archive.
Utilisation
Après compilation, nous trouvons dans notre répertoire le fichier de la bibliothèque (libschedattr.so.1.0), deux liens symboliques permettant d’y accéder, et deux fichiers exécutables.
[~]$ tar xjf schedattr.tar.bz2 [~]$ cd schedattr/ [schedattr]$ make gcc -c -fPIC -Wall schedattr.c -I. gcc -shared -Wl,-soname,libschedattr.so.1.0 schedattr.o -o libschedattr.so ln -sf libschedattr.so libschedattr.so.1 ln -sf libschedattr.so.1 libschedattr.so.1.0 gcc -Wall -I. -L. -o sched-getattr sched-getattr.c -lschedattr gcc -Wall -I. -L. -o sched-setattr sched-setattr.c -lschedattr [schedattr]$ ls -l total 60 -rwxrwxr-x 1 cpb cpb 7960 avril 5 06:27 libschedattr.so lrwxrwxrwx 1 cpb cpb 15 avril 5 06:27 libschedattr.so.1 -> libschedattr.so lrwxrwxrwx 1 cpb cpb 17 avril 5 06:27 libschedattr.so.1.0 -> libschedattr.so.1 -rw-rw-r-- 1 cpb cpb 726 avril 5 06:11 Makefile -rw-rw-r-- 1 cpb cpb 1685 avril 5 06:14 schedattr.c -rw-rw-r-- 1 cpb cpb 1465 avril 5 06:16 schedattr.h -rw-rw-r-- 1 cpb cpb 1664 avril 5 06:27 schedattr.o -rwxrwxr-x 1 cpb cpb 8873 avril 5 06:27 sched-getattr -rw-rw-r-- 1 cpb cpb 1892 avril 5 06:16 sched-getattr.c -rwxrwxr-x 1 cpb cpb 13108 avril 5 06:27 sched-setattr -rw-rw-r-- 1 cpb cpb 3604 avril 5 06:16 sched-setattr.c [schedattr]$
Pour que les programmes puissent fonctionner, il faut qu’ils soient capables de trouver la bibliothèque. Deux possibilités :
- vous copiez le fichier
libschedattr.so.1.0
dans/usr/local/lib
par exemple puis lancez la commandeldconfig
pour que les liens nécessaires y soient créés. - vous remplissez la variable d’environnement
LD_LIBRARY_PATH
avec le répertoire contenant la bibliothèque (ou le point pour représenter le répertoire courant) avant de lancer les commandes
C’est la seconde solution que je vais adopter.
sched-getattr
Commençons par vérifier le comportement de sched-getattr
. La variable $$
contient toujours le PID du shell courant.
[schedattr]$ export LD_LIBRARY_PATH=. [schedattr]$ echo $$ 16337 [schedattr]$ ./sched-getattr 16337 16337: Timesharing scheduling, nice=0
Le shell est ordonnancé en temps partagé avec une valeur de nice nulle, c’est normal. Modifions cette valeur.
[schedattr]$ renice -n +5 16337 16337 (process ID) old priority 0, new priority 5 [schedattr]$ ./sched-getattr 16337 16337: Timesharing scheduling, nice=5
Notre programme a vu la modification, l’appel-système sched_getattr()
semble fonctionner. Passons le shell en temps réel avec la commande chrt
et vérifions ce qu’indique sched-getattr
.
[schedattr]$ sudo chrt -pf 20 16337 [schedattr]$ ./sched-getattr 16337 16337: Realtime FIFO scheduling, priority=20
Parfait. Vérifions pour l’ordonnancement Round Robin.
[schedattr]$ sudo chrt -pr 40 16337 [schedattr]$ ./sched-getattr 16337 16337: Realtime RR scheduling, priority=40 [schedattr]$
sched-setattr
Nous allons maintenant vérifier le fonctionnement du programme sched-setattr
. Commençons par les ordonnancements temps partagé, temps réel Fifo et Round Robin en vérifiant le résultat du changement d’ordonnancement avec chrt
.
[schedattr]$ ./sched-setattr --help unknown --help scheduling... usage: ./sched-setattr R <priority> <pid> (RR) F <priority> <pid> (Fifo) D <Runtime> <Dealine> <Period> <pid> O <nice> <pid> (Other) [schedattr]$ sudo LD_LIBRARY_PATH=. ./sched-setattr O 0 16337 [schedattr]$ chrt -p 16337 pid 16337's current scheduling policy: SCHED_OTHER pid 16337's current scheduling priority: 0 [schedattr]$ sudo LD_LIBRARY_PATH=. ./sched-setattr R 10 16337 [schedattr]$ chrt -p 16337 pid 16337's current scheduling policy: SCHED_RR pid 16337's current scheduling priority: 10 [schedattr]$ sudo LD_LIBRARY_PATH=. ./sched-setattr F 20 16337 [schedattr]$ chrt -p 16337 pid 16337's current scheduling policy: SCHED_FIFO pid 16337's current scheduling priority: 20
Notez la syntaxe permettant d’initialiser une variable d’environnement spécialement pour exécuter la commande se trouvant sur le reste de la ligne. Ceci est nécessaire à cause du sudo
qui efface l’environnement avant de lancer la commande qu’on lui transmet.
Passons en ordonnancement deadline et vérifions avec chrt
.
[schedattr]$ sudo LD_LIBRARY_PATH=. ./sched-setattr D 1024 2048 4096 16337 [schedattr]$ chrt -p 16337 chrt: unknown scheduling policy chrt: échec d'obtention des attributs du PID 16337: Argument invalide pid 16337's current scheduling policy: [schedattr]$
Hé oui ! La commande chrt
ne connaît pas encore ce type d’ordonnancement. Elle échoue donc (et se plante un peu maladroitement…) en essayant d’interpréter les résultats obtenus avec l’ancien appel sched_getschedparam()
, le seul appel-système qu’elle connaisse. Mais nous pouvons vérifier le comportement avec sched_getattr()
:
[schedattr]$ ./sched-getattr 16337 16337: Deadline scheduling, runtime=1024, deadline=2048, period=4096 [schedattr]$
Conclusion
Le but de cet article est d’utiliser des appels-système nouveaux, inconnus de la bibliothèque C. Ce que l’on a vu ci-dessus pourrait s’appliquer à d’autres circonstances : invocation d’un appel-système personnalisé, utilisation d’une bibliothèque C ancienne sur un noyau récent, etc.
Nous avons obtenu deux programmes qui nous donnent accès au mécanisme d’ordonnancement temps réel deadline apparu dans le noyau 3.14. Il nous reste à comprendre comment fonctionne cet ordonnancement… Ce qui fera l’objet d’un prochain article.
Très instructif ! Ne pas oublier de mettre le prototype de syscall ! Ça me surprend de voir une fonction de ce type, j’ai toujours cru que cette partie était construite en assembleur.
Très bon article de contournement de ce temporaire manque de la libc.
Au prochain article sur le plus de ce type d’ordonnancement
Merci
Merci pour cet article.
J’attends la suite avec impatience 🙂
Thank you very much.
I really enjoy reading your articles. You are my hero.
Regards