Ressources des processus sous Linux

Ce forum est dédié à apprendre le développement de programmes user mode sur Linux

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 54
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

Ressources des processus sous Linux

Post by Hydraxx »

Ressources des processus sous Linux

Introduction

Sous Linux et les systèmes UNIX, chaque processus consomme différentes ressources du système :
  • du temps processeur ;
  • de la mémoire ;
  • des descripteurs de fichiers ;
  • de l’espace de pile ;
  • des processus ou threads ;
  • des signaux en attente ;
  • des files de messages ;
  • des ressources de planification temps réel.
Le noyau permet à un programme :
  • de mesurer les ressources déjà consommées ;
  • de consulter les limites imposées au processus ;
  • de modifier certaines de ces limites.
Les trois API principales étudiées dans ce chapitre sont :

Code: Select all

getrusage()
getrlimit()
setrlimit()
La fonction getrusage() sert à mesurer les ressources consommées.

Les fonctions getrlimit() et setrlimit() servent à consulter et modifier les limites de ressources.

1. Mesurer les ressources avec getrusage()

Prototype

Code: Select all

#include <sys/resource.h>

int getrusage(int who, struct rusage *usage);
Valeur de retour :
  • 0 en cas de succès ;
  • -1 en cas d’erreur, avec errno positionné.
Le paramètre who indique quelle consommation de ressources doit être récupérée.

RUSAGE_SELF

Code: Select all

getrusage(RUSAGE_SELF, &usage);
Cette valeur récupère les statistiques du processus appelant.

Les statistiques peuvent inclure les ressources consommées par ses threads.

RUSAGE_CHILDREN

Code: Select all

getrusage(RUSAGE_CHILDREN, &usage);
Cette valeur récupère les statistiques cumulées des processus enfants terminés qui ont été récupérés avec une fonction comme :

Code: Select all

wait()
waitpid()
waitid()
Un processus enfant encore actif n’est normalement pas inclus.

Un enfant terminé mais non encore récupéré peut également ne pas être pris en compte.

RUSAGE_THREAD

Code: Select all

getrusage(RUSAGE_THREAD, &usage);
Cette valeur récupère les statistiques du thread appelant uniquement.

Elle est spécifique à Linux et nécessite généralement :

Code: Select all

#define _GNU_SOURCE
avant les inclusions d’en-têtes.

2. La structure struct rusage

La fonction getrusage() remplit une structure de type :

Code: Select all

struct rusage
Cette structure contient plusieurs statistiques sur les ressources consommées.

Tous les champs ne sont pas forcément renseignés ou réellement utilisés sur toutes les implémentations UNIX.

Temps CPU utilisateur

Code: Select all

struct timeval ru_utime;
Ce champ contient le temps processeur passé en mode utilisateur.

Il correspond au temps utilisé pour exécuter le code normal du programme.

Temps CPU noyau

Code: Select all

struct timeval ru_stime;
Ce champ contient le temps processeur passé dans le noyau.

Il correspond principalement au temps consommé pendant les appels système.

Structure timeval

Code: Select all

struct timeval {
    time_t      tv_sec;
    suseconds_t tv_usec;
};
  • tv_sec : nombre de secondes ;
  • tv_usec : nombre de microsecondes.
Pour convertir une durée en secondes décimales :

Code: Select all

double secondes =
    usage.ru_utime.tv_sec +
    usage.ru_utime.tv_usec / 1000000.0;
Mémoire résidente maximale

Code: Select all

long ru_maxrss;
Ce champ représente la taille maximale de mémoire résidente utilisée par le processus.

Sous Linux, cette valeur est généralement exprimée en kilooctets.

La mémoire résidente correspond aux pages réellement présentes en mémoire physique.

Défauts de page mineurs

Code: Select all

long ru_minflt;
Nombre de défauts de page qui n’ont pas nécessité de lecture depuis un périphérique de stockage.

Exemples :
  • page déjà présente dans le cache ;
  • allocation paresseuse d’une nouvelle page ;
  • copie sur écriture.
Défauts de page majeurs

Code: Select all

long ru_majflt;
Nombre de défauts de page ayant nécessité une opération d’entrée-sortie.

Ils sont généralement plus coûteux que les défauts mineurs.

Opérations d’entrée bloc

Code: Select all

long ru_inblock;
Nombre d’opérations d’entrée effectuées via le système de fichiers ou un périphérique bloc.

Opérations de sortie bloc

Code: Select all

long ru_oublock;
Nombre d’opérations de sortie effectuées via le système de fichiers ou un périphérique bloc.

Changements de contexte volontaires

Code: Select all

long ru_nvcsw;
Nombre de changements de contexte volontaires.

Un changement volontaire se produit par exemple lorsqu’un thread :
  • attend un mutex ;
  • appelle sleep() ;
  • attend une entrée-sortie ;
  • se bloque sur une condition.
Changements de contexte involontaires

Code: Select all

long ru_nivcsw;
Nombre de changements de contexte imposés par le noyau.

Exemples :
  • expiration du quantum ;
  • préemption par un thread plus prioritaire ;
  • décision de l’ordonnanceur.
Autres champs historiques

La structure peut aussi contenir des champs comme :

Code: Select all

ru_ixrss
ru_idrss
ru_isrss
ru_nswap
ru_msgsnd
ru_msgrcv
ru_nsignals
Sur Linux, plusieurs de ces champs sont présents pour compatibilité mais ne sont pas forcément utilisés.

3. Exemple simple avec getrusage()

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>

int main(void)
{
    struct rusage usage;

    if (getrusage(RUSAGE_SELF, &usage) == -1) {
        perror("getrusage");
        return EXIT_FAILURE;
    }

    printf("Temps utilisateur : %ld.%06ld secondes\n",
           (long)usage.ru_utime.tv_sec,
           (long)usage.ru_utime.tv_usec);

    printf("Temps noyau : %ld.%06ld secondes\n",
           (long)usage.ru_stime.tv_sec,
           (long)usage.ru_stime.tv_usec);

    printf("Memoire residente maximale : %ld Ko\n",
           usage.ru_maxrss);

    printf("Defauts de page mineurs : %ld\n",
           usage.ru_minflt);

    printf("Defauts de page majeurs : %ld\n",
           usage.ru_majflt);

    printf("Changements volontaires : %ld\n",
           usage.ru_nvcsw);

    printf("Changements involontaires : %ld\n",
           usage.ru_nivcsw);

    return EXIT_SUCCESS;
}
4. Les informations disponibles dans /proc

Linux expose également de nombreuses informations dans le pseudo-système de fichiers :

Code: Select all

/proc
Pour un processus donné :

Code: Select all

/proc/PID/stat
/proc/PID/status
/proc/PID/limits
Exemples :

Code: Select all

cat /proc/self/status
cat /proc/self/limits
cat /proc/1234/stat
Le fichier :

Code: Select all

/proc/PID/limits
affiche les limites souples et dures du processus.

L’accès dépend des permissions et de l’identité du processus appelant.

5. Consulter les limites avec getrlimit()

Prototype

Code: Select all

#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim);
Valeur de retour :
  • 0 en cas de succès ;
  • -1 en cas d’erreur.
Le paramètre resource indique la ressource concernée.

Le paramètre rlim pointe vers une structure :

Code: Select all

struct rlimit {
    rlim_t rlim_cur;
    rlim_t rlim_max;
};
rlim_cur : limite souple

Code: Select all

rlim_cur
La limite souple est la limite actuellement appliquée au processus.

Lorsque cette limite est atteinte, le noyau peut :
  • faire échouer une opération ;
  • envoyer un signal ;
  • empêcher une nouvelle allocation ;
  • empêcher la création d’une nouvelle ressource.
rlim_max : limite dure

Code: Select all

rlim_max
La limite dure représente le plafond maximal que la limite souple peut atteindre.

Un processus non privilégié peut généralement :
  • diminuer sa limite souple ;
  • augmenter sa limite souple jusqu’à la limite dure ;
  • diminuer sa limite dure.
En revanche, il ne peut normalement pas augmenter une limite dure qu’il a abaissée.

Un processus privilégié disposant de la capacité :

Code: Select all

CAP_SYS_RESOURCE
peut modifier davantage les limites.

RLIM_INFINITY

La valeur :

Code: Select all

RLIM_INFINITY
indique qu’aucune limite pratique n’est imposée.

Exemple :

Code: Select all

if (limit.rlim_cur == RLIM_INFINITY) {
    printf("Limite souple illimitee\n");
}
6. Modifier les limites avec setrlimit()

Prototype

Code: Select all

#include <sys/resource.h>

int setrlimit(int resource, const struct rlimit *rlim);
Valeur de retour :
  • 0 en cas de succès ;
  • -1 en cas d’erreur.
Exemple :

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>

int main(void)
{
    struct rlimit limit;

    if (getrlimit(RLIMIT_NOFILE, &limit) == -1) {
        perror("getrlimit");
        return EXIT_FAILURE;
    }

    printf("Ancienne limite souple : %llu\n",
           (unsigned long long)limit.rlim_cur);

    printf("Ancienne limite dure : %llu\n",
           (unsigned long long)limit.rlim_max);

    limit.rlim_cur = 128;

    if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
        perror("setrlimit");
        return EXIT_FAILURE;
    }

    printf("Nouvelle limite souple : 128\n");

    return EXIT_SUCCESS;
}
Une limite souple ne peut jamais être supérieure à la limite dure :

Code: Select all

rlim_cur <= rlim_max
Sinon, setrlimit() échoue.

7. Héritage des limites

Les limites de ressources sont héritées par les processus enfants créés avec :

Code: Select all

fork()
Elles sont également conservées après :

Code: Select all

execve()
Cela permet à un processus parent de limiter un programme avant de l’exécuter.

Exemple logique :

Code: Select all

fork()
    |
    +-- enfant
          |
          +-- setrlimit()
          |
          +-- execve()
Cette technique est utile pour :
  • lancer un programme non fiable ;
  • construire un mini-sandbox ;
  • limiter un compilateur ;
  • limiter un serveur ;
  • empêcher une consommation excessive de mémoire ou de CPU.
8. Principales ressources contrôlables

RLIMIT_AS

Code: Select all

RLIMIT_AS
Limite la taille maximale de l’espace d’adressage virtuel du processus.

Cette limite peut affecter :

Code: Select all

malloc()
calloc()
realloc()
mmap()
mremap()
brk()
sbrk()
Lorsque la limite est atteinte, les allocations peuvent échouer avec :

Code: Select all

ENOMEM
Cette limite ne correspond pas uniquement à la mémoire physique utilisée.

Elle concerne l’ensemble de l’espace virtuel du processus.

RLIMIT_CORE

Code: Select all

RLIMIT_CORE
Limite la taille maximale d’un fichier core produit lors du plantage d’un processus.

Pour désactiver les core dumps :

Code: Select all

struct rlimit limit = {0, 0};

setrlimit(RLIMIT_CORE, &limit);
Une limite égale à zéro empêche normalement la création du fichier core.

RLIMIT_CPU

Code: Select all

RLIMIT_CPU
Limite le temps CPU consommé par un processus, en secondes.

Lorsque la limite souple est atteinte, le noyau envoie généralement :

Code: Select all

SIGXCPU
Le programme peut intercepter ce signal.

S’il continue à consommer du CPU, le noyau peut ensuite envoyer :

Code: Select all

SIGKILL
lorsque la limite dure est atteinte.

Exemple :

Code: Select all

struct rlimit limit;

limit.rlim_cur = 2;
limit.rlim_max = 4;

setrlimit(RLIMIT_CPU, &limit);
Ici :
  • vers 2 secondes de CPU, le processus reçoit SIGXCPU ;
  • vers 4 secondes de CPU, il peut être tué.
Attention : il s’agit du temps CPU réellement consommé, pas du temps écoulé sur une horloge murale.

RLIMIT_DATA

Code: Select all

RLIMIT_DATA
Limite la taille du segment de données du processus.

Cette limite peut notamment affecter :

Code: Select all

brk()
sbrk()
malloc()
Sur Linux, elle peut également influencer certaines allocations anonymes selon la version du noyau.

RLIMIT_FSIZE

Code: Select all

RLIMIT_FSIZE
Limite la taille maximale d’un fichier que le processus peut créer ou agrandir.

Si le processus dépasse cette limite, il peut recevoir :

Code: Select all

SIGXFSZ
Les appels d’écriture peuvent échouer.

Exemple :

Code: Select all

struct rlimit limit = {
    .rlim_cur = 1024,
    .rlim_max = 1024
};

setrlimit(RLIMIT_FSIZE, &limit);
Le processus ne pourra normalement pas créer un fichier dépassant 1024 octets.

RLIMIT_MEMLOCK

Code: Select all

RLIMIT_MEMLOCK
Limite la quantité de mémoire que le processus peut verrouiller en RAM.

Fonctions concernées :

Code: Select all

mlock()
mlockall()
munlock()
munlockall()
mmap()
shmctl()
Une page verrouillée ne peut normalement pas être envoyée dans l’espace d’échange.

Cette fonctionnalité est utile pour :
  • les programmes temps réel ;
  • les données cryptographiques sensibles ;
  • les programmes devant éviter les défauts de page.
RLIMIT_MSGQUEUE

Code: Select all

RLIMIT_MSGQUEUE
Limite la quantité de mémoire utilisée par les files de messages POSIX appartenant à l’utilisateur réel.

API associées :

Code: Select all

mq_open()
mq_send()
mq_receive()
mq_close()
mq_unlink()
Cette limite est spécifique à Linux.

RLIMIT_NICE

Code: Select all

RLIMIT_NICE
Contrôle jusqu’à quelle valeur favorable un processus non privilégié peut modifier sa priorité nice.

API associées :

Code: Select all

nice()
getpriority()
setpriority()
Une valeur nice plus faible correspond généralement à une priorité plus élevée.

RLIMIT_NOFILE

Code: Select all

RLIMIT_NOFILE
Limite le nombre maximal de descripteurs de fichiers ouverts par un processus.

Cette limite concerne notamment :
  • les fichiers ;
  • les sockets ;
  • les pipes ;
  • les événements comme eventfd ;
  • les descripteurs epoll ;
  • les descripteurs inotify.
Lorsque la limite est atteinte, une ouverture peut échouer avec :

Code: Select all

EMFILE
Exemple :

Code: Select all

struct rlimit limit = {
    .rlim_cur = 32,
    .rlim_max = 32
};

setrlimit(RLIMIT_NOFILE, &limit);
Le plus grand numéro de descripteur utilisable est normalement inférieur à la limite.

RLIMIT_NPROC

Code: Select all

RLIMIT_NPROC
Limite le nombre de processus ou threads appartenant à un utilisateur réel.

Lorsque la limite est atteinte :

Code: Select all

fork()
clone()
pthread_create()
peuvent échouer avec :

Code: Select all

EAGAIN
Important : cette limite est comptée pour l’utilisateur réel, pas uniquement pour le processus courant.

Si l’utilisateur possède déjà beaucoup de processus, une limite faible peut être atteinte immédiatement.

RLIMIT_RSS

Code: Select all

RLIMIT_RSS
Cette limite concerne théoriquement la mémoire résidente maximale.

Sous Linux, elle est historiquement peu appliquée ou ignorée dans de nombreux cas.

Il ne faut donc pas compter dessus pour construire une limitation mémoire fiable.

RLIMIT_RTPRIO

Code: Select all

RLIMIT_RTPRIO
Définit la priorité temps réel maximale qu’un processus non privilégié peut demander.

API associées :

Code: Select all

sched_setscheduler()
sched_setparam()
pthread_setschedparam()
Politiques temps réel possibles :

Code: Select all

SCHED_FIFO
SCHED_RR
RLIMIT_RTTIME

Code: Select all

RLIMIT_RTTIME
Limite le temps CPU consommé par un processus soumis à une politique temps réel sans effectuer d’appel système bloquant.

La valeur est exprimée en microsecondes.

Lorsque la limite souple est atteinte, le processus peut recevoir :

Code: Select all

SIGXCPU
Lorsque la limite dure est atteinte, il peut recevoir :

Code: Select all

SIGKILL
RLIMIT_SIGPENDING

Code: Select all

RLIMIT_SIGPENDING
Limite le nombre de signaux pouvant être placés en attente pour un utilisateur réel.

Elle concerne principalement les signaux envoyés avec :

Code: Select all

sigqueue()
Les signaux temps réel peuvent être mis en attente plusieurs fois, contrairement aux signaux traditionnels.

RLIMIT_STACK

Code: Select all

RLIMIT_STACK
Limite la taille maximale de la pile du processus.

Un dépassement de pile peut provoquer :

Code: Select all

SIGSEGV
Pour intercepter proprement un signal lorsque la pile principale est épuisée, il est recommandé d’utiliser une pile de signal alternative :

Code: Select all

sigaltstack()
Puis d’installer le gestionnaire avec :

Code: Select all

sigaction()
et l’option :

Code: Select all

SA_ONSTACK
Depuis certaines versions de Linux, RLIMIT_STACK limite aussi l’espace utilisé pour transmettre les arguments et l’environnement à execve().

9. Afficher une limite proprement

Le type :

Code: Select all

rlim_t
n’est pas nécessairement un simple int.

Pour l’afficher, on peut effectuer une conversion explicite.

Code: Select all

#include <stdio.h>
#include <sys/resource.h>

static void afficher_limite(const char *nom, int resource)
{
    struct rlimit limit;

    if (getrlimit(resource, &limit) == -1) {
        perror("getrlimit");
        return;
    }

    printf("%s\n", nom);

    if (limit.rlim_cur == RLIM_INFINITY) {
        printf("  Souple : illimitee\n");
    } else {
        printf("  Souple : %llu\n",
               (unsigned long long)limit.rlim_cur);
    }

    if (limit.rlim_max == RLIM_INFINITY) {
        printf("  Dure   : illimitee\n");
    } else {
        printf("  Dure   : %llu\n",
               (unsigned long long)limit.rlim_max);
    }
}
Utilisation :

Code: Select all

int main(void)
{
    afficher_limite("Descripteurs", RLIMIT_NOFILE);
    afficher_limite("Pile", RLIMIT_STACK);
    afficher_limite("Memoire virtuelle", RLIMIT_AS);

    return 0;
}
10. Exemple : limiter le nombre de processus

Code: Select all

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    struct rlimit limit;

    if (getrlimit(RLIMIT_NPROC, &limit) == -1) {
        perror("getrlimit");
        return EXIT_FAILURE;
    }

    printf("Ancienne limite souple : %llu\n",
           (unsigned long long)limit.rlim_cur);

    printf("Ancienne limite dure : %llu\n",
           (unsigned long long)limit.rlim_max);

    limit.rlim_cur = 30;

    if (limit.rlim_max < limit.rlim_cur) {
        limit.rlim_cur = limit.rlim_max;
    }

    if (setrlimit(RLIMIT_NPROC, &limit) == -1) {
        perror("setrlimit");
        return EXIT_FAILURE;
    }

    for (int i = 0; i < 100; i++) {
        pid_t pid = fork();

        if (pid == -1) {
            perror("fork");
            break;
        }

        if (pid == 0) {
            sleep(10);
            _exit(EXIT_SUCCESS);
        }

        printf("Enfant cree : PID=%ld\n", (long)pid);
    }

    while (wait(NULL) > 0) {
    }

    if (errno != ECHILD) {
        perror("wait");
    }

    return EXIT_SUCCESS;
}
La création des enfants finit par échouer lorsque la limite est atteinte.

Cependant, RLIMIT_NPROC prend en compte tous les processus ou threads appartenant à l’utilisateur réel.

11. Valeurs non représentables

Sur certaines anciennes implémentations, le type utilisé par le noyau pour stocker une limite pouvait être plus grand que le type rlim_t visible par l’application.

Une limite pouvait alors être impossible à représenter exactement.

Certaines implémentations définissent :

Code: Select all

RLIM_SAVED_CUR
RLIM_SAVED_MAX
Ces valeurs servent à représenter une limite souple ou dure qui ne tient pas dans le type disponible.

Sur les systèmes Linux modernes 64 bits, ce problème est rarement rencontré.

12. Erreurs courantes

EINVAL

Peut survenir lorsque :
  • la ressource est invalide ;
  • la limite souple est supérieure à la limite dure ;
  • une valeur fournie est incohérente.
EPERM

Peut survenir lorsqu’un processus non privilégié tente :
  • d’augmenter une limite dure ;
  • de dépasser la limite autorisée par le système ;
  • de modifier une ressource nécessitant des privilèges.
EFAULT

Peut survenir si le pointeur vers la structure est invalide.

ENOMEM

Peut être retournée par une allocation mémoire lorsqu’une limite comme RLIMIT_AS ou RLIMIT_DATA est atteinte.

EMFILE

Indique que le processus a atteint sa limite de descripteurs de fichiers.

EAGAIN

Peut indiquer que la limite de processus ou de threads a été atteinte.

13. Équivalent avec le shell

Le shell fournit généralement la commande :

Code: Select all

ulimit
Exemples :

Code: Select all

ulimit -a
Affiche les limites courantes.

Code: Select all

ulimit -n 128
Fixe la limite souple du nombre de descripteurs ouverts.

Code: Select all

ulimit -c 0
Désactive les fichiers core pour le shell et ses futurs processus enfants.

Code: Select all

ulimit -t 5
Limite le temps CPU à cinq secondes.

Les limites définies dans le shell sont héritées par les programmes lancés depuis celui-ci.

14. Différence entre limites de ressources et priorités

Une limite de ressources indique la quantité maximale qu’un processus peut consommer.

Une priorité indique plutôt dans quel ordre le processus doit être exécuté par rapport aux autres.

Exemples de priorités :

Code: Select all

nice()
setpriority()
sched_setscheduler()
pthread_setschedparam()
Exemples de limites :

Code: Select all

RLIMIT_CPU
RLIMIT_AS
RLIMIT_NOFILE
RLIMIT_NPROC
Les deux mécanismes sont complémentaires.

15. Comparaison avec Windows

Sous Windows, les Job Objects remplissent un rôle partiellement comparable.

Ils permettent notamment de limiter :
  • la mémoire ;
  • le temps CPU ;
  • le nombre de processus ;
  • certains comportements des processus enfants.
API Windows correspondantes :

Code: Select all

CreateJobObject()
SetInformationJobObject()
AssignProcessToJobObject()
QueryInformationJobObject()
Exemples de structures Windows :

Code: Select all

JOBOBJECT_EXTENDED_LIMIT_INFORMATION
JOBOBJECT_BASIC_LIMIT_INFORMATION
JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
Sous Linux, setrlimit() agit essentiellement sur un processus et ses descendants par héritage.

Pour des limitations plus avancées portant sur un groupe de processus, Linux propose également les cgroups.

16. Exemple complet : exécuter une commande avec des limites

Code: Select all

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>

static int fixer_limite(int resource,
                        rlim_t soft,
                        rlim_t hard)
{
    struct rlimit limit;

    limit.rlim_cur = soft;
    limit.rlim_max = hard;

    if (setrlimit(resource, &limit) == -1) {
        perror("setrlimit");
        return -1;
    }

    return 0;
}

int main(int argc, char *argv[])
{
    if (argc < 2) {
        fprintf(stderr,
                "Utilisation : %s commande [arguments...]\n",
                argv[0]);

        return EXIT_FAILURE;
    }

    pid_t pid = fork();

    if (pid == -1) {
        perror("fork");
        return EXIT_FAILURE;
    }

    if (pid == 0) {
        if (fixer_limite(RLIMIT_CPU, 2, 3) == -1) {
            _exit(EXIT_FAILURE);
        }

        if (fixer_limite(RLIMIT_NOFILE, 32, 32) == -1) {
            _exit(EXIT_FAILURE);
        }

        if (fixer_limite(RLIMIT_AS,
                         256ULL * 1024 * 1024,
                         256ULL * 1024 * 1024) == -1) {
            _exit(EXIT_FAILURE);
        }

        execvp(argv[1], &argv[1]);

        perror("execvp");
        _exit(EXIT_FAILURE);
    }

    int status;

    if (waitpid(pid, &status, 0) == -1) {
        perror("waitpid");
        return EXIT_FAILURE;
    }

    if (WIFEXITED(status)) {
        printf("Code de sortie : %d\n",
               WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        printf("Processus termine par le signal : %d\n",
               WTERMSIG(status));
    }

    return EXIT_SUCCESS;
}
Ce programme :
  • crée un processus enfant ;
  • limite son temps CPU ;
  • limite ses descripteurs ;
  • limite son espace mémoire virtuel ;
  • exécute la commande demandée ;
  • attend sa terminaison.
17. API essentielles du chapitre

Mesure des ressources

Code: Select all

getrusage()
Consultation des limites

Code: Select all

getrlimit()
Modification des limites

Code: Select all

setrlimit()
Gestion des processus enfants

Code: Select all

fork()
execve()
execvp()
wait()
waitpid()
waitid()
Gestion des signaux

Code: Select all

sigaction()
sigaltstack()
sigqueue()
Ordonnancement et priorité

Code: Select all

nice()
getpriority()
setpriority()
sched_setscheduler()
sched_setparam()
pthread_setschedparam()
Mémoire

Code: Select all

malloc()
calloc()
realloc()
brk()
sbrk()
mmap()
mremap()
mlock()
mlockall()
munlock()
munlockall()
Files de messages POSIX

Code: Select all

mq_open()
mq_send()
mq_receive()
mq_close()
mq_unlink()
18. Structures essentielles

Code: Select all

struct rusage
struct rlimit
struct timeval
19. Constantes essentielles

Sélection de la cible de getrusage()

Code: Select all

RUSAGE_SELF
RUSAGE_CHILDREN
RUSAGE_THREAD
Valeurs spéciales

Code: Select all

RLIM_INFINITY
RLIM_SAVED_CUR
RLIM_SAVED_MAX
Limites de ressources

Code: Select all

RLIMIT_AS
RLIMIT_CORE
RLIMIT_CPU
RLIMIT_DATA
RLIMIT_FSIZE
RLIMIT_MEMLOCK
RLIMIT_MSGQUEUE
RLIMIT_NICE
RLIMIT_NOFILE
RLIMIT_NPROC
RLIMIT_RSS
RLIMIT_RTPRIO
RLIMIT_RTTIME
RLIMIT_SIGPENDING
RLIMIT_STACK
Signaux importants

Code: Select all

SIGXCPU
SIGXFSZ
SIGSEGV
SIGKILL
20. Résumé final

La fonction :

Code: Select all

getrusage()
permet de mesurer les ressources déjà consommées par :
  • le processus courant ;
  • ses enfants terminés ;
  • le thread courant sous Linux.
Elle fournit notamment :
  • le temps CPU utilisateur ;
  • le temps CPU noyau ;
  • la mémoire résidente maximale ;
  • les défauts de page ;
  • les opérations bloc ;
  • les changements de contexte.
La fonction :

Code: Select all

getrlimit()
permet de consulter la limite souple et la limite dure d’une ressource.

La fonction :

Code: Select all

setrlimit()
permet de modifier ces limites dans la mesure autorisée par les privilèges du processus.

La limite souple est la limite actuellement appliquée.

La limite dure est le plafond maximal de la limite souple.

Les limites sont héritées par fork() et conservées après execve().

Les limites les plus utiles sont souvent :

Code: Select all

RLIMIT_CPU
RLIMIT_AS
RLIMIT_NOFILE
RLIMIT_NPROC
RLIMIT_STACK
RLIMIT_CORE
RLIMIT_FSIZE
Ces mécanismes permettent de protéger le système contre un processus consommant trop de CPU, de mémoire, de fichiers ou d’autres ressources.

Who is online

Users browsing this forum: No registered users and 0 guests