Systèmes d’exploitation

Slides:



Advertisements
Présentations similaires
Module Systèmes d’exploitation
Advertisements

Module Systèmes d’exploitation
Module Systèmes d’exploitation
GEF 435 Principes des systèmes d’exploitation
Premier programme en C :
La boucle for : init7.c et init71.c
Le Concept du programme enregistré
Synchronisation des processus père - fils
GEF 435 Principes des systèmes d’exploitations
GEF 435 Principes des systèmes dexploitation Structure des systèmes dexploitation (Tanenbaum 1.7)
GEF 435 Principes des systèmes dexploitation Concepts des Systèmes dexploitation (Tanenbaum 1.5)
GEF 435 Principes des systèmes dexploitation Appels de système (Tanenbaum 1.6)
GEF 243B Programmation informatique appliquée
C.
Le Concept du programme enregistré
Mémoire & Processus Cours SE - SRC
Parallel Programming in C with MPI and OpenMP
Système d’Exploitation
Systèmes d'exploitations Les redirections d'entrées/sorties GRARI Mounir ESTO Année 2011.
Principes de programmation (suite)
Points importants de la semaine Les fonctions. La portée. La passage par copie. Les tableaux.
Structures de données linéaires
Récursivité.
Algorithmique et Programmation
CSI3525: Concepts des Langages de Programmation Notes # 12: Implementation des Sous-Programmes ( Lire Chapitre 9 )
1 Threads et Lightweight Processes Chapitre 5 En français on utilise parfois flots ou fils pour threads. Votre manuel préfère le mot anglais thread : terminologie.
8PRO100 Éléments de programmation Allocation dynamique de la mémoire.
Système d’exploitation
Course Critique Race Condition
Introduction au paradigme objet Concepts importants surcharge (overload) redéfinition (override) Définition d’une classe Définition des attributs.
Quest-ce quune classe dallocation? Une classe dallocation détermine la portée et la durée de vie dun objet ou dune fonction.
Les pointeurs Modes d’adressage de variables. Définition d’un pointeur. Opérateurs de base. Opérations élémentaires. Pointeurs et tableaux. Pointeurs et.
Test et débogage Tests unitaires. Gestion d’erreurs. Notion d’état, de pré-condition et de post-condition. Assertion. Traces de programme. Débogueur et.
Chapitre XI Gestion des erreurs et exceptions. 2 La gestion des erreurs et exceptions De nombreux problèmes peuvent survenir pendant lexécution dun programme:
Module 2 : Préparation de l'analyse des performances du serveur
CSI3531 – Labo 1 Lobservation du comportement de processus.
ÉLÉMENTS DE BASE UNIX.
Leçon 1 : notion dobjet IUP Génie Informatique Besançon Méthode et Outils pour la Programmation Françoise Greffier Université de Franche-Comté.
Programme de baccalauréat en informatique Programmation Orientée Objets IFT Thierry EUDE Module 6. Gestion des erreurs et des exceptions : Fonctionnement.
Mécanismes d'exécution et de communication
Procédures et fonctions
Plan cours La notion de pointeur et d’adresse mémoire.
Structures de données IFT-2000 Abder Alikacem La récursivité Département d’informatique et de génie logiciel Édition Septembre 2009.
Qu’est-ce qu’un système d’exploitation ?
Systèmes d'exploitations Processus
La notion de type revisitée en POO
Communication avec l’environnement
Interactions entre Processus
Tutorat en bio-informatique
La programmation système
Programmation Système et Réseau
Introduction au langage C Fonctions et Procédures
CSI 3525, Implémentation des sous-programmes, page 1 Implémentation des sous-programmes L’environnement dans les langages structurés en bloc La structure.
Classe 1 CSI2572 Autres modificateurs de déclaration de variables: & volatile & register & static & auto & extern & const volatile Indique au compilateur.
Les variables fichiers. Le type fichier On manipule les fichiers par l’intermédiaire de structures FILE décrites dans stdio.h FILE *monFichier; –Nom physique.
Conception de Programmes - IUT de Paris - 1ère année Quelques éléments du langage C++ Les références La surcharge de fonctions Les fonctions «
Patricia Renault UPMC 2005/2006
Cours Système LI324 Les Interruptions Cours Système LI324
Système de gestion fichiers
8PRO107 Éléments de programmation Les adresses et les pointeurs.
Les Processus.
Scripts et fonctions Instructions de contrôle
Architecture et technologie des ordinateurs II
Systèmes d’exploitation Processus conclusion Modèle conceptuel de processus Pour masquer les effets des interruptions, les SE fournissent un modèle conceptuel.
Chapitre 9 Les caractères.
Architecture d’un ordinateur
Gestion des Tâches Les Processus. Un système multitâches La carte mère comporte Le Processeur (calcul et attente) Les jeux de composants spécialisés (entrées-sorties.
Chapitre 12 Surveillance des ressources et des performances Module S41.
1 UNIX AVANCE Yves PAGNOTTE – Janvier – LES PROCESSUS SOUS UNIX.
Transcription de la présentation:

Systèmes d’exploitation Les processus

Introduction Concept de processus est le  important dans un SE Processus = abstraction d’un programme en cours d’exécution Tous les ordinateurs modernes peuvent exécuter plusieurs tâches à la fois (ex : programme en cours de calcul + affichage sur un terminal + impression) MAIS le processeur, à un instant donné, n’exécute réellement qu’un seul programme Dans un système multiprogrammé, le processeur passe d’un programme à un autre en exécutant chaque programme pendant quelques dizaines de millisecondes  impression de parallélisme Ce parallélisme est qualifié de pseudo-parallélisme Attention : ne pas confondre avec le parallélisme qui s’effectue au niveau matériel (nécessite plusieurs processeurs) Le contrôle de plusieurs activités en pseudo-parallélisme est une tâche difficile qui a fait l’objet de nombreuses améliorations pour obtenir le modèle actuel

Le modèle des processus (1) Un processus est un programme qui s’exécute et qui possède son compteur ordinal, ses registres et ses variables Conceptuellement, chaque processus a son propre processeur virtuel En réalité, le processeur commute entre plusieurs processus Cette commutation rapide est appelée multiprogrammation Un seul compteur ordinal A B C D Multiprogrammation de 4 processus Commutation de processus A B C D 4 compteurs ordinaux Modèle conceptuel de 4 processus séquentiels indépendants Temps processus D — — C — — B — — A — — Un seul programme actif à un instant donné

Le modèle des processus (2) Comme le processeur commute entre les processus, la vitesse d’exécution d’un processus ne sera pas uniforme et variera vraissemblablement si les mêmes processus sont exécutés à nouveau Attention : Ne pas confondre programme et processus (ex : confection d’un gâteau et piqûre d’abeille) L’idée clé est qu’un processus est une activité d’un certain type qui possède un programme, des données, en entrée et en sortie, ainsi qu’un état courant Un seul processeur peut être partagé entre plusieurs processus en se servant d’un algorithme d’ordonnancement qui détermine quand il faut suspendre un processus pour en servir un autre

Hiérarchie entre les processus Les SE qui font appel au concept de processus doivent permettre de créer et détruire dynamiquement les processus 2 exemples : Unix et MS-DOS Unix : Les processus sont créés par l’appel système fork Le fork crée une copie conforme du processus appelant À la suite du fork, le processus père continue à s’exécuter en « parallèle » avec son fils Le processus père peut créer d’autres fils et ces processus fils peuvent eux-mêmes avoir des fils  Arborescence de processus  hiérarchie MS-DOS : Un appel système pour charger un fichier binaire en mémoire et l’exécuter en tant que processus fils Contrairement à Unix, MS-DOS suspend le père jusqu’à ce que le fils ai terminé son exécution  pas de pseudo-parallélisme

Les différents états d’un processus Les processus, bien qu’étant des entités indépendantes doivent parfois interagir avec d’autres processus (ex : cat fic1 fic2 | grep mot) L’ordre et la vitesse d’exécution des processus peut amener un des processus à se bloquer (ex : le grep est prêt à s’exécuter mais ne peut le faire faute de données) Un processus se bloque lorsqu’il ne peut pas, pour une raison logique, poursuivre son exécution (ex : attente de données) Un processus élu peut être arrêté et mis en situation d’attente (on dit qu’il est prêt), même s’il peut poursuivre son exécution (ex : le SE décide d’allouer le processeur à un autre processus) Ces 2 situations sont totalement différentes : Dans le premier cas, la suspension est inhérente au problème Dans le second cas, il s’agit d’une caractéristique technique du système 1. Élu (en cours d’exécution) 3 états possibles : 2. Prêt (suspendu pour permettre l’exécution d’un autre processus) 3. Bloqué (attendant un événement extérieur pour pouvoir continuer)

Les transitions entre les états Élu Prêt Bloqué 4 transitions peuvent avoir lieu entre les états La transition 1 se produit lorsqu’un processus ne peut plus poursuivre son exécution 1 1. Le processus se bloque en attente de données La transition 2 a lieu lorsque l’ordonnanceur décide que le processus en cours s’est exécuté pendant une durée suffisante ; cette opération est appelée réquisition 2 2. L’ordonnanceur choisit un autre processus La transition 3 se produit lorsque tous les processus ont obtenu leur quota de temps et qu’il faut relancer le premier processus 3. L’ordonnanceur choisit le processus initial 3 4 La transition 4 est réalisée si l’évènement extérieur attendu par un processus se produit 4. Les données deviennent disponibles Les transitions 2 et 3 sont provoqués par l’ordonnanceur de processus (module du SE) Le rôle de l’ordonnanceur est très important : il choisit le processus à exécuter ainsi que le moment où il faut le lancer ; il constitue le niveau le plus bas du SE Il existe  stratégies d’ordonnancement, qui seront étudiées dans la suite du cours

Le modèle des processus (suite) Le modèle des processus permet de mieux comprendre ce qui se passe à l’intérieur du SE : Une partie des processus exécutent les programmes des utilisateurs Les autres processus font partie du système et gèrent les tâchent telles que les requêtes au gestionnaire de fichiers ou les opérations sur disques Le nouveau modèle obtenu : 1 n-1 n Ordonnanceur (scheduler) … Processus L’ordonnanceur constitue le niveau le + bas du SE Il est surmonté d’une multitude de processus La gestion des interruptions, la suspension et la relance des processus sont déportées dans l’ordonnanceur Le reste du SE est structuré sous forme de processus

La réalisation des processus Pour mettre en œuvre pratiquement le modèle de processus, le SE a une table (tableau de structures) : la table des processus (TP) dont chaque entrée correspond à un processus particulier Chaque entrée comporte des informations sur : l’état du processus son compteur ordinal son pointeur de pile son allocation mémoire l’état des fichiers ouverts … et tout ce qui doit être sauvé lorsqu’un processus passe de l’état élu à l’état prêt Le contenu de la table des processus varie d’un système à un autre En général, les informations concernent la : La gestion du processus La gestion mémoire La gestion des fichiers

La table des processus Unix Quelques champs typiques de la table des processus Gestion des processus Gestion de la mémoire Gestion des fichiers Registres, compteur ordinal Mot d’état du programme Pointeur de pile État du processus Date de lancement du processus Temps CPU utilisé Temps CPU des fils Date de la prochaine alarme Pointeurs sur files de message Bits des signaux en attente Identificateur de processus (pid) Divers indicateurs Pointeur sur le segment de code Pointeur sur segment de données Pointeur sur segment BSS Statut de fin d’exécution Statut de signal Processus père Groupe du processus uid réel, uid effectif gid réel, gid effectif Table de bits des signaux Masque UMASK Répertoire racine Répertoire de travail Descripteurs de fichiers uid effectif gid effectif Paramètres des appels systèmes

Les processus Unix Un processus Unix se décompose en : Un espace d’adressage (visible par l’utilisateur/le programmeur) Le bloc de contrôle du processus (BCP) lui-même décomposé en : Une entrée dans la TP du noyau struct proc définie dans <sys/proc.h> Une struct user appelée zone u définie dans <sys/user.h> Les processus Unix apportent La multiplicité d’exécution (plusieurs processus peuvent être l’exécution d’un même prog.) La protection des exécutions (un processus ne peut exécuter que ses instructions propres et ce de façon séquentielle) Les processus Unix communiquent entre eux et avec le reste du monde grâce aux appels systèmes la TP est interne au noyau : P1 P5 P5 P1 TP noyau les processus

Création d’un processus Unix Cette création est réalisée par l’appel système : int fork(void); Chaque processus est identifié par un numéro unique, son PID Tous les processus (sauf le processus de pid=0) sont créés par un appel à fork Le processus qui appelle le fork est appelé processus père Le nouveau processus est appelé processus fils Tout processus a 1 seul père mais peut avoir 0 ou plusieurs fils Le processus de pid=0 est créé « manuellement » au démarrage de la machine ce processus joue un rôle spécial pour le système (swappeur,gestionnaire de pages) pour le bon fonctionnement des prog. utilisant fork, ce processus reste toujours utilisé ce procéssus crée grâce à un appel fork, le processus init de pid=1 Le processus de pid=1 est l’ancêtre de tous les autres processus (le processus 0 ne réalisant plus de fork) il a notamment pour rôle de recueillir tous les processus orphelins de père (ceci afin de collecter les informations à la mort de chaque processus)

Format d’un fichier exécutable Les compilateurs permettent de créer des fichiers exécutables Ces fichiers ont un format particulier qui permet au noyau de les transformer en processus Une en-tête qui décrit l’ensemble du fichier, ses attributs et sa carte des sections Une section TEXT qui contient le code (en langage machine) Une section DATA codée en langage machine qui comporte 2 parties : Une partie pour les données initialisées Une autre pour les données non initialisées (BSS) Éventuellement d’autres sections: Table des symboles pour le débuggeur Images Icones Tables des chaînes …

Chargement/changement d’un exécutable L’appel système execve change l’exécutable du processus courant en chargeant un nouvel exécutable Pour chaque section, de l’exécutable une région mémoire est alloué; soit au moins : les régions code et données initialisées mais aussi les régions des piles et du tas La pile est une pile de structures qui sont empilées et dépilées lors de l’appel ou le retour de fonction le pointeur de pile, un des registres de l’UC donne la profondeur courante de la pile le code du programme gère les extensions de pile, c’est le noyau qui alloue l’espace nécessaire à ces extensions un processus Unix pouvant s’exécuter dans 2 modes (noyau, utilisateur), une pile privée sera utilisée dans chaque mode Le tas est une zone où est réalisée l’allocation dynamique avec les fonctions : Xalloc()

Structure interne des processus Adresse haute = 0xFFFFFFFF argc, argv, envp Tas   Pile Données non initialisées (BSS) Données initialisées Texte initialisé par exec lu par exec Adresse basse = 0

zone u et table des processus Tous les processus sont associés à une entrée dans la TP qui interne au noyau De +, le noyau alloue pour chaque processus une structure appelée zone u qui contient les données privées du processus (uniquement manipulable par le noyau) La TP, permet d’accéder à la table des régions par processus (TRP) Ce double niveau d’indirection permet le partage des régions Dans une organisation en mémoire virtuelle, la TRP est matérialisée logiquement dans la table des pages Les structures de régions dans TRP contiennent des infos sur le type, les droits d’accès et la localisation (adresses en mémoire ou adresses sur disque) de la région Seule la zone u du processus courant est manipulable par le noyau, les autres sont inaccessibles L’adresse de la zone u est placée dans le mot d’état du processus

Le contexte d’un processus Le contexte d’un processus est l’ensemble des données qui permettent de reprendre l’exécution d’un processus qui a été interrompu Il est constitué de : son état son mot d’état, en particulier : la valeur des registres actifs le compteur ordinal les valeurs des variables globales statiques ou dynamiques son entrée dans la TP sa zone u les piles utilisateurs et systèmes les zones de code et de données Le noyau et ses variables ne font partie du contexte d’aucun processus ! L’exécution d’un processus se fait dans son contexte Quand il y a changement de processus courant, il y a réalisation d’une commutation de mot d’état et d’un changement de contexte

Contexte d’unité centrale Fonctions de très bas niveau, fondamentales pour pouvoir programmer un SE Pour être exécuté et donner naissance à un processus, un programme et ses données doivent être chargées en mémoire centrale de l’UC L’UC comprend des circuits logiques qui effectuent les instructions mais aussi des mémoires appelés registres : L’accumulateur (reçoit le résultat d’une instruction) Le registre d’instruction (contient l’instruction en cours) Le compteur ordinal (adresse de l’instruction en mémoire) Le registre d’adresse Les registres de données (utilisées pour lire/écrire une donnée à une adresse spécifiée) Les registres d’état du processeur (actif, mode (user/sys), vecteur d’interruptions, …) Les registres d’état du processus (droits, adresses, priorités, …) Ces registres forment le contexte d’unité centrale d’un processus

Commutation de mot d’état Pour pouvoir exécuter un nouveau processus, il faut sauvegarder le contexte d’unité centrale du processus courant (mot d’état), puis charger le nouveau mot d’état Cette opération est appelée commutation de mot d’état Cette commutation doit se faire de manière non interruptible ! Cette « super-instruction » utilise 2 adresses : l’adresse de sauvegarde du mot d’état l’adresse de lecteur du nouveau mot d’état Le compteur ordinal faisant partie du mot d’état, ce changement provoque l’exécution dans le nouveau processus Les fonctions setjmp/longjmp permettent de sauvegarder et de réinitialiser le contexte d’unité central du processus courant, en particulier le pointeur de pile

Les interruptions Une interruption est une commutation de mot d’état provoquée par un signal produit par le matériel Ce signal est la conséquence d’un évènement extérieur ou intérieur, il modifie l’état d’un indicateur qui est régulièrement testé par l’UC Une fois le signal détecté, on utilise le vecteur d’interruptions pour identifier la cause et réaliser la tâche demandée 3 grands types d’interruptions : Externes (indépendantes du processus) : pannes, interventions de l’utilisateur Déroutements : erreur interne du processeur (débordement, div/0, …) sauvegarde sur disque de l’image mémoire : core dumped Appels systèmes : accès disque, demande d’E/S, … Il existe plusieurs niveaux d’interruptions, ce qui permet au système de sélectionner l’interruption à traiter en priorité

Les interruptions sous Unix 6 niveaux d’interruptions : L’horloge est la plus prioritaire dans un système Unix Nature de l’interruption Fonction de traitement horloge clockintr 1 disques diskintr 2 console ttyintr 3 autres périphériques devintr 4 appel système sottintr 5 autre interruption otherintr

La cascade d’interruptions ! Si durant le traitement d’une interruption, une autre interruption se produit et que ceci se répète durant le traitement de la nouvelle interruption : le système ne fait plus progresser le processus en cours, ni les interruptions ! Nécessité de pouvoir retarder ou annuler une interruption  2 mécanismes : le masquage et le désarmement d’un niveau d’interruption Masquer = ignorer temporairement un niveau d’interruption Désarmer = rendre le positionnement de l’interruption caduque (impossible pour les déroutements)

États d’un processus (cas d’un système de gestion mémoire par swap) Listes des états d’un processus : :Le processus s’exécute en mode utilisateur Le processus s’exécute en mode noyau Le processus est prêt Le processus est endormi en mémoire centrale Le processus est prêt en zone swap Le processus est endormi en zone swap Le processus passe du mode noyau au mode utilisateur mais est préempté (bien que le processus soit prêt, il est retiré du traitement pour les autres processus progressent) Naissance d’un processus, ce processus n’est pas encore prêt, il n’est pas encore endormi, c’est l’état initial de tous processus sauf le swappeur Zombie : le processus vient de réaliser un exit, il apparaît uniquement dans la TP où il est conservé le temps que son père récupère le code de retour et d’autres informations de gestion (ex : tps d’exécution) L’état « zombie » est l’état final des processus, il reste dans cet état jusqu’à ce que le père lise leur valeur de retour (status) à l’aide l’appel système wait()

Diagramme d’état des processus 1 5 3 6 4 9 7 8 2 Bloqué en zone swap Prêt en zone swap fork Création Prêt en mémoire Préempté Exécution en mode utilisateur Exécution en mode noyau Zombie Bloqué (endormi) en mémoire Mémoire centrale Swap Examiner et traiter les signaux Examiner les signaux Appel système interruption Gestion interruption exit Retour au mode utilisateur préemption sleep swapin swapout Mémoire insuffisante Mémoire suffisante Ordonnancement du processus wakeup

La TP Unix La TP est localisée dans la mémoire du noyau TP = Tableau de struct proc (<sys/proc.h>) Cette structure contient les informations qui doivent toujours être accessibles par le noyau : État (cf diagramme) Adresse de la zone u Adresses : taille et localisation en mémoire pid et ppid : valeurs initialisées en état 8 uid Événement : descripteur de l’événement attendu lorsque le processus est endormi (bloqué) Priorités : utilisés par l’ordonnanceur Vecteurs d’interruptions du processus : ensemble des signaux reçus mais non traités Divers : compteurs (ex: tps CPU pour faire payer le temps de calcul), alarme Ces informations peuvent être obtenues à partir de la commande shell ps ou par consultation du pseudo système de fichiers /proc (et pour certaines d’entre elles, par différents appels systèmes)

La zone u La zone u est utilisée lorsque un processus s’exécute (mode noyau ou utilisateur) Une unique zone u est accessible à la fois : celle du processus en cours d’exécution (états 1 et 2) La zone u est de type struct user définie dans <sys/user.h>, elle contient : Pointeur sur la structure de processus de la TP uid réel et effectif : détermine les privilèges donnés au processus Compteurs de temps (user et system) Terminal : terminal de contrôle du processus (s’il existe) Erreur : dernière erreur rencontrée pendant un appel système Retour : valeur de retour du dernier appel système E/S : structures associées au E/S Répertoires courant et racine (cf. chroot()) Table des descripteurs Limites (cf. ulimit en Bourne Shell et limit en csh) umask : masque de création de fichiers Ces informations ne sont accessibles que par une réponse du processus lui-même et donc par l’utilisation d’appels systèmes !

Les informations temporelles #include <sys/time.h> clock_t times (struct tms * buffer); times remplit la structure pointée par buffer avec des informations sur le temps machine utilisé en état 1 et 2 Struct tms { clock_t tms_utime; /* user time */ clock_t tms_stime; /* system time */ clock_t tms_cutime; /* user time, children */ clock_t tms_csutime; /* system time, children */ }; Contient des temps indiqués en microsecondes, la précision dépend de l’ordinateur

Changement des répertoires #include <unistd.h> int chroot(const char* path); Permet de définir un nouveau point de départ pour les références absolues (commençant par /). La référence .. de ce répertoire racine étant associée à lui-même, il n’est donc pas possible de sortir du sous-arbre défini par chroot Les appels suivants permettent de changer le répertoire de travail du processus : int chdir(const char* path); int fchdir(int fd);

Récupération du pid #include <unistd.h> pid_t getpid(void); pid_t getppid(void); pid_t getpgrp(void); pid_t getpgrp2(pid_t pid); L’appel à getpid retourne le pid du processus courant getppid, le pid du processus père getpgrp, le pid du groupe du processus courant getpgrp2, le pid du groupe du processus pid (si pid=0, alors identique à getpgrp)

Identification de l’utilisateur L’uid d’un processus est l’identification de l’utilisateur exécutant le processus Le système utilise 3 uid : euid : uid effective utilisé pour les tests d’accès ruid : uid réelle suid : uid sauvegardée, pour pouvoir revenir en arrière #include <sys/types.h> #include <unistd.h> int setuid(uid_t uid) Fonctionnement : si euid=0 (root) alors les trois uid sont positionés à la valeur de uid, sinon si uid=ruid ou suid alors euid prend la valeur uid (ruid et suid ne changent pas), sinon RIEN ! (pas de changements) La commande setreuid permet de changer le ruid, elle est utilisée pendant le login, seul le super utilisateur peut l’exécuter avec succès Pour les goupes : int setgid(gid_t gid)

Tailles limites d’un processus #include <unistd.h> long ulimit(int cmd, …); La commande cmd est : UL_GETFIZE : retourne la taille maximum des fichiers en blocs UL_SETFSIZE : positionne cette valeur avec le deuxième argument UL_GETMAXBRK : valeur maximale pour l’appel d’allocation dynamique de mémoire : brk. Ces valeurs sont héritées du processus père Remarque : cet appel système n’est pas implémenté dans les noyaux 2.0 des systèmes Linux

Manipulation de la taille du segment de données #include <unistd.h> int brk(void* endds); void* sbrk(ptrdiff_t incr); brk positionne la fin du segment de données à l’adresse spécifiée endds doit être supérieur à la fin du segment de texte et 16ko avant la fin de la pile sbrk incrémente l’espace de données du programme de incr octets sbrk n’est pas un appel système, juste une fonction de la bibliothèque C Remarques : brk et sbrk ne sont pas définis dans le C standard et sont volontairement exclus des standards POSIX Il ne faut pas les utiliser conjointement aux fonctions d’allocation standard : malloc, calloc, realloc, free

Manipulation de la valeur de nice La valeur de nice d’un processus indique la priorité du processus pour l’ordonnancement Plus la valeur est petite, plus le processus est prioritaire La valeur de de nice est comprise entre 0 et 39 Seul le super utilisateur peut spécifier une valeur de nice négative #include <unistd.h> int nice(int valeur); La commande shell renice permet de changer le « nice » d’un processus actif

Manipulation de la valeur umask L’appel umask permet de spécifier quels droits doivent être interdits en cas de création de fichiers #include <unistd.h> int umask(int mask); umask fixe le masque de création de fichiers à la valeur : mask & 0777 Les bits contenus dans le masque sont éliminés de la valeur 0666 pour créer les nouvelles permissions ex : mask=0022  0666 & ~0022 = 0644 = rw-r--r-- Cet appel système n’échoue jamais et la valeur précédente du masque est renvoyée La commande umask existe également en shell

L’appel système fork L’appel système fork permet la création d’un processus clône du processus courant. #include <unistd.h> pid_t fork(void); DEUX valeurs de retour en cas de succès ! Dans le processus père, la valeur de retour est égale au pid du fils Dans le processus fils, la valeur de retour est égale à zéro Si échec (seul le processus père existe), la valeur de retour est égale à –1 Les pid et ppid sont les seules informations différentes entre les deux processus Les deux processus poursuivent leur exécution à l’instruction qui suit le fork Utilisation courante : pid_t pid; pid=fork(); if (pid>0) {/* processus père */ } else if (pid==0) {/*processus fils*/} else {/* Traitement d’erreur */}

Les appels systèmes exec (1) #include <unistd.h> int execl(char* path,char* arg0,char* arg1, …, NULL); int execv(char* path,char* arg[]); int execle(char* path,char* arg0,…, NULL, char* envp[]); int execve(char* path,char* arg[],char* envp[]); int execlp(char* file,char* arg0,char* arg1, …, NULL); int execvp(char* file,char* arg[]); Toutes ces fonctions sont « identiques » et diffèrent simplement par le mode de passage des paramètres Les différents noms des fonctions exec sont mnémoniques : l : liste d’arguments v : arguments sous forme de vecteur p : recherche du fichier avec la variable d’environnement PATH e : transmission d’un environnement en dernier paramètre, en remplacement de l’environnement courant

Les appels systèmes exec (2) Primitives Format d’argument Passage d’environnement Recherche avec PATH execl execv execle execve execlp execvp Liste Tableau Automatique Manuel Non Oui La famille des fonctions exec remplace l’image mémoire du processus en cours par un nouveau processus. Informations conservées par le processus : pid, ppid, pgid, ruid, suid, euid, nice, groupe d’accès, répertoires courant et racine, terminal de contrôle, utilisation et limites des ressources, umask, masques des signaux, signaux en attente, table des descripteurs de fichiers, verrous, session Valeur de retour : en cas de succès AUCUNE le code ayant fait l’exec n’existe plus, en cas d’échec –1

Lancement d’une commande #include <stdlib.h> int system(const char * commande); Crée un nouveau processus « /bin/sh » qui exécute la commande (/bin/sh –c commande) Le processus appelant cette fonction reste bloqué jusqu’à la fin de l’exécution du processus Ce mécanisme est très coûteux et n’est pas un appel système La valeur de retour est 127 si l’appel système execve pour /bin/sh échoue, -1 si une autre erreur, ou le code de retour de la commande sinon

Terminaison d’un processus _exit : primitive de terminaison de processus bas niveau #include <unistd.h> void _exit(int valeur); elle ferme les descripteurs ouverts par open, opendir ou hérités du processus père la valeur est fournie au processus père qui la récupère après l’appel système wait cette valeur est le code de retour de processus en shell cette primitive est automatiquement appelée à la fin de la fonction main (sauf en cas d’appels récursifs de main) Exit : fonction de terminaison de processus de stdlib #include <stdlib.h> void exit(int valeur); elle lance les fonctions définies par atexit ferme l’ensemble des descripteurs ouverts grâce à la bibliothèque standard (fopen) détruit les fichiers fabriqués par la primitive tmpfile appelle _exit avec valeur

La primitive atexit Console shell Cette primitive (non système) permet de spécifier des fonctions à appeler en fin d’exécution, elles sont lancées par exit dans l’ordre inverse de leur positionnement par atexit #include <stdlib.h> void atexit(void (*fonction) (void)); Exemple : void bob(void){printf(“coucou\n”);} void bib(void){printf(“cuicui ”);} main(int argc) { atexit(bob);atexit(bib); if (argc – 1) exit(0); else _exit(O); } $ gcc –o atexit atexit.c $ atexit $ atexit unargument cuicui coucou $ Console shell

Attente de la mort d’un fils #include <sys/types.h> #include <sys/wait.h> pid_t wait (int* status) pid_t waitpid(pid_t pid, int* status, int options) La fonction wait suspend l’exécution du processus courant jusqu’à ce qu’un fils se termine (ou jusqu’à réception d’un signal) Si un processus fils est déjà mort (il est zombie) la fonction revient immédiatement Toutes les ressources utilisées par le fils sont libérées La fonction waitpid suspend l’exécution du processus courant jusqu’à ce que le processus fils de numéro pid se termine (ou jusqu’à réception d’un signal) La valeur de pid peut être : < -1 : attente la fin de n’importe quel processus fils appartenant au groupe d’ID pid -1 : attendre n’importe quel fils (identique au wait) 0 : attendre la fin de n’importe quel processus fils du même groupe appelant > 0 : attendre la fin du processus de numéro pid   options, la plus utile : WNOHANG qui permet de ne pas bloquer si aucun fils n’est mort Si status  NULL, les informations sur la terminaison du fils y sont stockées WIFEXITED(status) : est non nul si le fils s’est terminé normalement WEXITSTATUS(status) : donne le code retour du fils tel qu’il l’a mentionné lors de l’appel _exit(retour)[valide uniquement si WIFEXITED(status)0]

Gestion des erreurs Dès lors que l’on effectue des appels systèmes, il est important de contrôler TOUTES les valeurs de retour Nous sommes aidés dans cette tâche par la bibliothèque C <errno.h> #include <errno.h> perror(const char *s) La fonction perror affiche un message sur la sortie standard des erreurs, décrivant la dernière erreur rencontrée durant un appel système La chaîne s est imprimée en premier suivie d’un : et du message d’erreur approprié Le numéro de l’erreur est obtenu à partir de la variable externe errno qui contient le code d’erreur lorsqu’un problème survient, mais qui n’est PAS effacé lorsqu’un appel réussi