<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>http://os-vps418.infomaniak.ch:1250/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hatat</id>
	<title>Wiki du LAMA (UMR 5127) - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="http://os-vps418.infomaniak.ch:1250/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hatat"/>
	<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php/Sp%C3%A9cial:Contributions/Hatat"/>
	<updated>2026-05-21T06:25:48Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5773</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5773"/>
		<updated>2012-09-14T13:36:24Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Passer une machine de NFS vers AFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 &amp;gt; sudo apt-get install libpam-krb5 heimdal-clients libpam-afs-session&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = lama.univ-savoie.fr&lt;br /&gt;
                admin_server = lama.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
 [domain_realm]&lt;br /&gt;
        www.lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
 &amp;gt; sudo apt-get install openafs-client openafs-krb5 libpam-afs-session&lt;br /&gt;
&lt;br /&gt;
Peut-être aussi &lt;br /&gt;
&lt;br /&gt;
 &amp;gt; sudo apt-get install openafs-modules-dkms&lt;br /&gt;
&lt;br /&gt;
Cellule AFS : lama.univ-savoie.fr&lt;br /&gt;
Taille du cache : Christophe veut un cache monstrueux (500 Mo par exemple, dépend de la taille de /var/cache/openafs).&lt;br /&gt;
&lt;br /&gt;
Dans /etc/openafs/CellServDB, virer tout et laisser uniquement :&lt;br /&gt;
 &amp;gt;lama.univ-savoie.fr&lt;br /&gt;
 193.48.123.134 # lama.univ-savoie.fr&lt;br /&gt;
&lt;br /&gt;
Puis faire (si vous le voulez des liens pour les homes) :&lt;br /&gt;
&lt;br /&gt;
 &amp;gt; sudo rm /home&lt;br /&gt;
 &amp;gt; sudo rm /home2&lt;br /&gt;
 &amp;gt; sudo ln -s /afs/lama.univ-savoie.fr/user /home&lt;br /&gt;
 &amp;gt; sudo ln -s /afs/lama.univ-savoie.fr/user /home2&lt;br /&gt;
&lt;br /&gt;
Enfin, ajouter la ligne&lt;br /&gt;
&lt;br /&gt;
 auth   optional   pam_afs_session.so&lt;br /&gt;
&lt;br /&gt;
à la fin des deux fichiers &#039;&#039;&#039;/etc/pam.d/common-auth&#039;&#039;&#039; et &#039;&#039;&#039;/etc/pam.d/common-session&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Sur MAC OS X 10.7 (marche peut-être avec 10.5 et 10.6) ==&lt;br /&gt;
&lt;br /&gt;
* Le fichier &amp;lt;code&amp;gt;/etc/krb5.conf&amp;lt;/code&amp;gt; est à nommer &amp;lt;code&amp;gt;/Library/Preferences/edu.mit.Kerberos&amp;lt;/code&amp;gt;&lt;br /&gt;
* Il faut installer openAFS depuis la page : [http://www.openafs.org/macos.html http://www.openafs.org/macos.html] et mettre &amp;lt;code&amp;gt;lama.univ-savoie.fr&amp;lt;/code&amp;gt; comme cellule par défaut&lt;br /&gt;
* le fichier &amp;lt;code&amp;gt;/etc/openafs/CellServDB&amp;lt;/code&amp;gt; est alors à placer dans &amp;lt;code&amp;gt;/var/db/openafs/etc/&amp;lt;/code&amp;gt;. Remarque : on peut éditer ce ficher depuis le panneaux de préférence d&#039;openAFS ... Sauf que ça semble ne pas marcher (sans doute un pb de permission ?).&lt;br /&gt;
* redémarrer le MAC pour être sur de redémarrer openAFS (on doit pouvoir éviter ça)&lt;br /&gt;
* dans le panneau de préférence openAFS cocher &#039;&#039;Use aklog&#039;&#039; et &#039;&#039;get credential at login time&#039;&#039;&lt;br /&gt;
* pour plus de confort créer un lien où bon vous semble pour votre home sur le serveur lama qui est dans &amp;lt;code&amp;gt;/afs/lama.univ-savoie.fr/user/mon_login&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vérification ==&lt;br /&gt;
&lt;br /&gt;
Logger vous sur la machine et taper &#039;&#039;&#039;klist&#039;&#039;&#039;.&lt;br /&gt;
La réponse doit ressembler à:&lt;br /&gt;
&lt;br /&gt;
 Credentials cache: FILE:/tmp/krb5cc_1066_T1K6vd&lt;br /&gt;
        Principal: raffalli@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
  Issued           Expires          Principal&lt;br /&gt;
 Aug 14 13:34:19  Aug 15 13:34:19  krbtgt/LAMA.UNIV-SAVOIE.FR@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 Aug 14 13:34:19  Aug 15 13:34:19  afs@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
Les deux dernières lignes vous indique que vous avez un ticket kerberos sur le &lt;br /&gt;
royaume du LAMA et un ticket kerberos pour les serveur OpenAFS.&lt;br /&gt;
&lt;br /&gt;
Tapez aussi &#039;&#039;&#039;tokens&#039;&#039;&#039; avec une réponse attendue qui ressemble à:&lt;br /&gt;
&lt;br /&gt;
 Tokens held by the Cache Manager:&lt;br /&gt;
 &lt;br /&gt;
 User&#039;s (AFS ID 1066) tokens for afs@lama.univ-savoie.fr [Expires Aug 15 13:34]&lt;br /&gt;
   --End of list--&lt;br /&gt;
&lt;br /&gt;
On vois sur l&#039;avant dernière ligne, le jeton afs qui autorise la connection au serveur&lt;br /&gt;
et qui a été obtenu auprès du serveur afs en présentant le ticket kerberos afs.&lt;br /&gt;
&lt;br /&gt;
= Possibilités supplémentaires =&lt;br /&gt;
&lt;br /&gt;
== Avoir des droits depuis son compte local ==&lt;br /&gt;
&lt;br /&gt;
Si vous avez un compte local sur votre machine, vous pouvez avoir simultanément les &lt;br /&gt;
droits sur votre compte local et sur le compte sur lama.univ-savoie.fr.&lt;br /&gt;
&lt;br /&gt;
Pour cela, une fois loggé sur votre compte local, tapé&lt;br /&gt;
&lt;br /&gt;
 &amp;gt; kinit login_sur_lama&lt;br /&gt;
 &amp;gt; aklog&lt;br /&gt;
&lt;br /&gt;
La première commande sert à obtenir un ticket Kerberos (on&lt;br /&gt;
peut vérifir son ticket avec klist) la second commande présente le&lt;br /&gt;
ticket pour opbtenir un jeton afs.&lt;br /&gt;
&lt;br /&gt;
Après ça vous devriez avoir les droits sur &lt;br /&gt;
&lt;br /&gt;
 /afs/lama.univ-savoie.fr/user/login_sur_lama&lt;br /&gt;
&lt;br /&gt;
== Taille du cache ==&lt;br /&gt;
&lt;br /&gt;
Il n&#039;y a aucune raison que la taille du cache ne soit pas&lt;br /&gt;
du même ordre de grandeur que la taille de vos fichiers personnels.&lt;br /&gt;
&lt;br /&gt;
Il faut juste faire attention, le cache est par défaut dans&lt;br /&gt;
/var/cache/openafs et il ne faudrait pas qu&#039;un cahce de 20Go&lt;br /&gt;
remplisse votre partition /. Donc il faut mettre le cache là où il y a assez de place&lt;br /&gt;
(avec un lien symbolique ou en changeant le cache par défaut).&lt;br /&gt;
&lt;br /&gt;
La configuration du cache (taille max et position) est dans&lt;br /&gt;
&lt;br /&gt;
 /etc/openafs/cacheinfo&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/pam.d/gnome-screensaver (ou /etc/pam.d/xscreensaver):&lt;br /&gt;
&lt;br /&gt;
 auth    [success=ok default=1] pam_krb5.so minimum_uid=1000&lt;br /&gt;
 auth    [default=4]        pam_afs_session.so nopag&lt;br /&gt;
 auth    [success=3 default=ignore]      pam_unix.so nullok_secure try_first_pass&lt;br /&gt;
 # here&#039;s the fallback if no module succeeds&lt;br /&gt;
 auth    requisite                       pam_deny.so&lt;br /&gt;
 # prime the stack with a positive return value if there isn&#039;t one already;&lt;br /&gt;
 # this avoids us returning an error just because nothing sets a success code&lt;br /&gt;
 # since the modules above will each just jump around&lt;br /&gt;
 auth    required                        pam_permit.so&lt;br /&gt;
 # and here are more per-package modules (the &amp;quot;Additional&amp;quot; block)&lt;br /&gt;
 auth    optional                        pam_cap.so &lt;br /&gt;
 &lt;br /&gt;
 auth optional pam_gnome_keyring.so&lt;br /&gt;
&lt;br /&gt;
= SSh et AFS =&lt;br /&gt;
&lt;br /&gt;
Ce sujet a une page dédiée : [[SshAvecAfs]]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5576</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5576"/>
		<updated>2012-07-12T16:26:02Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Renouveler les tickets avec l&amp;#039;écran de veille */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5 heimdal-clients&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
 [domain_realm]&lt;br /&gt;
        printers-lama.local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install openafs-client openafs-krb5 libpam-afs-session&lt;br /&gt;
&lt;br /&gt;
Cellule AFS : lama.univ-savoie.fr&lt;br /&gt;
Taille du cache : Christophe veut un cache monstrueux (500 Mo par exemple, dépend de la taille de /var/cache/openafs).&lt;br /&gt;
&lt;br /&gt;
Dans /etc/openafs/CellServDB, virer tout et laisser uniquement :&lt;br /&gt;
 &amp;gt;lama.univ-savoie.fr&lt;br /&gt;
 192.168.144.134 # printers-lama.local.univ-savoie.fr&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Le # n&#039;indique pas un commentaire !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 # sudo rm /home&lt;br /&gt;
 # sudo rm /home2&lt;br /&gt;
 # sudo ln -s /afs/lama.univ-savoie.fr/user /home&lt;br /&gt;
 # sudo ln -s /afs/lama.univ-savoie.fr/user /home2&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/pam.d/gnome-screensaver :&lt;br /&gt;
&lt;br /&gt;
 auth    [success=ok default=1] pam_krb5.so minimum_uid=1000&lt;br /&gt;
 auth    [default=4]        pam_afs_session.so nopag&lt;br /&gt;
 auth    [success=3 default=ignore]      pam_unix.so nullok_secure try_first_pass&lt;br /&gt;
 # here&#039;s the fallback if no module succeeds&lt;br /&gt;
 auth    requisite                       pam_deny.so&lt;br /&gt;
 # prime the stack with a positive return value if there isn&#039;t one already;&lt;br /&gt;
 # this avoids us returning an error just because nothing sets a success code&lt;br /&gt;
 # since the modules above will each just jump around&lt;br /&gt;
 auth    required                        pam_permit.so&lt;br /&gt;
 # and here are more per-package modules (the &amp;quot;Additional&amp;quot; block)&lt;br /&gt;
 auth    optional                        pam_cap.so &lt;br /&gt;
 &lt;br /&gt;
 auth optional pam_gnome_keyring.so&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5575</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5575"/>
		<updated>2012-07-12T16:20:32Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Installer OpenAFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5 heimdal-clients&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
 [domain_realm]&lt;br /&gt;
        printers-lama.local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install openafs-client openafs-krb5 libpam-afs-session&lt;br /&gt;
&lt;br /&gt;
Cellule AFS : lama.univ-savoie.fr&lt;br /&gt;
Taille du cache : Christophe veut un cache monstrueux (500 Mo par exemple, dépend de la taille de /var/cache/openafs).&lt;br /&gt;
&lt;br /&gt;
Dans /etc/openafs/CellServDB, virer tout et laisser uniquement :&lt;br /&gt;
 &amp;gt;lama.univ-savoie.fr&lt;br /&gt;
 192.168.144.134 # printers-lama.local.univ-savoie.fr&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Le # n&#039;indique pas un commentaire !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 # sudo rm /home&lt;br /&gt;
 # sudo rm /home2&lt;br /&gt;
 # sudo ln -s /afs/lama.univ-savoie.fr/user /home&lt;br /&gt;
 # sudo ln -s /afs/lama.univ-savoie.fr/user /home2&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5574</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5574"/>
		<updated>2012-07-12T16:19:15Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Installer OpenAFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5 heimdal-clients&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
 [domain_realm]&lt;br /&gt;
        printers-lama.local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install openafs-client openafs-krb5&lt;br /&gt;
&lt;br /&gt;
Cellule AFS : lama.univ-savoie.fr&lt;br /&gt;
Taille du cache : Christophe veut un cache monstrueux (500 Mo par exemple, dépend de la taille de /var/cache/openafs).&lt;br /&gt;
&lt;br /&gt;
Dans /etc/openafs/CellServDB, virer tout et laisser uniquement :&lt;br /&gt;
 &amp;gt;lama.univ-savoie.fr&lt;br /&gt;
 192.168.144.134 # printers-lama.local.univ-savoie.fr&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Le # n&#039;indique pas un commentaire !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 # sudo rm /home&lt;br /&gt;
 # sudo rm /home2&lt;br /&gt;
 # sudo ln -s /afs/lama.univ-savoie.fr/user /home&lt;br /&gt;
 # sudo ln -s /afs/lama.univ-savoie.fr/user /home2&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5573</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5573"/>
		<updated>2012-07-12T16:16:41Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Kerbériser la machine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5 heimdal-clients&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
 [domain_realm]&lt;br /&gt;
        printers-lama.local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        local.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .lama.univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        .univ-savoie.fr = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install openafs-client openafs-krb5&lt;br /&gt;
&lt;br /&gt;
Cellule AFS : lama.univ-savoie.fr&lt;br /&gt;
Taille du cache : Christophe veut un cache monstrueux (500 Mo par exemple, dépend de la taille de /var/cache/openafs).&lt;br /&gt;
&lt;br /&gt;
Dans /etc/openafs/CellServDB, virer tout et laisser uniquement :&lt;br /&gt;
 &amp;gt;lama.univ-savoie.fr&lt;br /&gt;
 192.168.144.134 # printers-lama.local.univ-savoie.fr&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Le # n&#039;indique pas un commentaire !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5572</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5572"/>
		<updated>2012-07-12T16:11:55Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Installer OpenAFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5 heimdal-clients&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install openafs-client openafs-krb5&lt;br /&gt;
&lt;br /&gt;
Cellule AFS : lama.univ-savoie.fr&lt;br /&gt;
Taille du cache : Christophe veut un cache monstrueux (500 Mo par exemple, dépend de la taille de /var/cache/openafs).&lt;br /&gt;
&lt;br /&gt;
Dans /etc/openafs/CellServDB, virer tout et laisser uniquement :&lt;br /&gt;
 &amp;gt;lama.univ-savoie.fr&lt;br /&gt;
 192.168.144.134 # printers-lama.local.univ-savoie.fr&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Le # n&#039;indique pas un commentaire !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5571</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5571"/>
		<updated>2012-07-12T16:05:16Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Kerbériser la machine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5 heimdal-clients&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5570</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5570"/>
		<updated>2012-07-12T16:03:13Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Kerbériser la machine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 &lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5569</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5569"/>
		<updated>2012-07-12T16:03:01Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Kerbériser la machine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
 # sudo apt-get install libpam-krb5&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5568</id>
		<title>MettreAFS</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=MettreAFS&amp;diff=5568"/>
		<updated>2012-07-12T15:58:09Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Passer une machine de NFS vers AFS =&lt;br /&gt;
&lt;br /&gt;
== Kerbériser la machine ==&lt;br /&gt;
&lt;br /&gt;
== Installer OpenAFS ==&lt;br /&gt;
&lt;br /&gt;
== Renouveler les tickets avec l&#039;écran de veille ==&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5566</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5566"/>
		<updated>2012-07-10T14:00:30Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Pour chaque serveur SSH */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Sur le client ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
 Host *&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Pour chaque serveur SSH ==&lt;br /&gt;
&lt;br /&gt;
On veut pouvoir se connecter sur d45.lama.univ-savoie.fr depuis une autre machine, grâce au ticket Kerberos que l&#039;on détient dans le royaume LAMA.UNIV-SAVOIE.FR.&lt;br /&gt;
&lt;br /&gt;
On pourrait utiliser les clefs publiques/clefs privées de SSH, mais on a mieux avec Kerberos, car en plus le ticket AFS suit.&lt;br /&gt;
&lt;br /&gt;
=== Sur le serveur du LAMA ===&lt;br /&gt;
&lt;br /&gt;
Le serveur SSH de d45.lama.univ-savoie.fr a besoin d&#039;un principal qui l&#039;identifie dans le royaume. Ce principal c&#039;est host/d45.lama.univ-savoie.fr@LAMA.UNIV-SAVOIE.FR et il faut le créer sur le serveur du LAMA.&lt;br /&gt;
&lt;br /&gt;
 # kadmin -l&lt;br /&gt;
 kadmin&amp;gt; add -r host/d45.lama.univ-savoie.fr@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 Max ticket life [1 week]:&lt;br /&gt;
 Max renewable life [1 month 1 day]:&lt;br /&gt;
 Principal expiration time [never]:&lt;br /&gt;
 Password expiration time [never]:&lt;br /&gt;
 Attributes []:&lt;br /&gt;
 kadmin&amp;gt; ext_keytab -k /tmp/d45.keytab host/d45.lama.univ-savoie.fr&lt;br /&gt;
 kadmin&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
Ne pas oublier de virer à la fin le fichier /tmp/d45.keytab (c&#039;est une clef secrète) !&lt;br /&gt;
&lt;br /&gt;
=== Sur la machine à kerbériser ===&lt;br /&gt;
&lt;br /&gt;
Il faut activer le support Kerberos sur d45.lama.univ-savoie.fr dans SSH ; dans /etc/ssh/sshd_config :&lt;br /&gt;
 # Kerberos options&lt;br /&gt;
 KerberosAuthentication yes&lt;br /&gt;
 KerberosOrLocalPasswd yes&lt;br /&gt;
 KerberosTicketCleanup yes&lt;br /&gt;
 &lt;br /&gt;
 # GSSAPI options&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPICleanupCredentials yes&lt;br /&gt;
 GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
Et il faut lui donner son principal secret :&lt;br /&gt;
&lt;br /&gt;
 # scp www.lama.univ-savoie.fr:/tmp/d45.keytab /etc/krb5.keytab&lt;br /&gt;
 # chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5565</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5565"/>
		<updated>2012-07-10T13:54:02Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Sur le client ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
 Host *&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Pour chaque serveur SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Sur le serveur du LAMA ===&lt;br /&gt;
&lt;br /&gt;
 # kadmin -l&lt;br /&gt;
 kadmin&amp;gt; add -r host/d45.lama.univ-savoie.fr@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 Max ticket life [1 week]:&lt;br /&gt;
 Max renewable life [1 month 1 day]:&lt;br /&gt;
 Principal expiration time [never]:&lt;br /&gt;
 Password expiration time [never]:&lt;br /&gt;
 Attributes []:&lt;br /&gt;
 kadmin&amp;gt; ext_keytab -k /tmp/d45.keytab host/d45.lama.univ-savoie.fr&lt;br /&gt;
 kadmin&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
Ne pas oublier de virer à la fin le fichier /tmp/d45.keytab (c&#039;est une clef secrète) !&lt;br /&gt;
&lt;br /&gt;
=== Sur la machine à kerbériser ===&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/sshd_config :&lt;br /&gt;
 # Kerberos options&lt;br /&gt;
 KerberosAuthentication yes&lt;br /&gt;
 KerberosOrLocalPasswd yes&lt;br /&gt;
 KerberosTicketCleanup yes&lt;br /&gt;
 &lt;br /&gt;
 # GSSAPI options&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPICleanupCredentials yes&lt;br /&gt;
 GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
Puis récupérer le keytab :&lt;br /&gt;
&lt;br /&gt;
 # scp www.lama.univ-savoie.fr:/tmp/d45.keytab /etc/krb5.keytab&lt;br /&gt;
 # chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5564</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5564"/>
		<updated>2012-07-10T13:53:06Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Sur le client ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
 Host *&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Pour chaque serveur SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la machine à kerbériser ===&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/sshd_config :&lt;br /&gt;
 # Kerberos options&lt;br /&gt;
 KerberosAuthentication yes&lt;br /&gt;
 KerberosOrLocalPasswd yes&lt;br /&gt;
 KerberosTicketCleanup yes&lt;br /&gt;
 &lt;br /&gt;
 # GSSAPI options&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPICleanupCredentials yes&lt;br /&gt;
 GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
=== Sur le serveur du LAMA ===&lt;br /&gt;
&lt;br /&gt;
 # kadmin -l&lt;br /&gt;
 kadmin&amp;gt; add -r host/d45.lama.univ-savoie.fr@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 Max ticket life [1 week]:&lt;br /&gt;
 Max renewable life [1 month 1 day]:&lt;br /&gt;
 Principal expiration time [never]:&lt;br /&gt;
 Password expiration time [never]:&lt;br /&gt;
 Attributes []:&lt;br /&gt;
 kadmin&amp;gt; ext_keytab -k /tmp/d45.keytab host/d45.lama.univ-savoie.fr&lt;br /&gt;
 kadmin&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
=== De nouveau sur la machine à Kerbériser ===&lt;br /&gt;
 # scp www.lama.univ-savoie.fr:/tmp/d45.keytab /etc/krb5.keytab&lt;br /&gt;
 # chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5563</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5563"/>
		<updated>2012-07-10T13:52:45Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Sur le client ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
 Host *&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Pour chaque serveur SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la machine à kerbériser ===&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/sshd_config :&lt;br /&gt;
 # Kerberos options&lt;br /&gt;
 KerberosAuthentication yes&lt;br /&gt;
 KerberosOrLocalPasswd yes&lt;br /&gt;
 KerberosTicketCleanup yes&lt;br /&gt;
&lt;br /&gt;
 # GSSAPI options&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPICleanupCredentials yes&lt;br /&gt;
 GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
=== Sur le serveur du LAMA ===&lt;br /&gt;
&lt;br /&gt;
 # kadmin -l&lt;br /&gt;
 kadmin&amp;gt; add -r host/d45.lama.univ-savoie.fr@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 Max ticket life [1 week]:&lt;br /&gt;
 Max renewable life [1 month 1 day]:&lt;br /&gt;
 Principal expiration time [never]:&lt;br /&gt;
 Password expiration time [never]:&lt;br /&gt;
 Attributes []:&lt;br /&gt;
 kadmin&amp;gt; ext_keytab -k /tmp/d45.keytab host/d45.lama.univ-savoie.fr&lt;br /&gt;
 kadmin&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
=== De nouveau sur la machine à Kerbériser ===&lt;br /&gt;
 # scp www.lama.univ-savoie.fr:/tmp/d45.keytab /etc/krb5.keytab&lt;br /&gt;
 # chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5562</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5562"/>
		<updated>2012-07-10T13:46:34Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Sur le client ==&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
 Host *&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Pour chaque serveur SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la machine à kerbériser ===&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/sshd_config :&lt;br /&gt;
 # Kerberos options&lt;br /&gt;
 KerberosAuthentication yes&lt;br /&gt;
 KerberosOrLocalPasswd yes&lt;br /&gt;
 KerberosTicketCleanup yes&lt;br /&gt;
&lt;br /&gt;
 # GSSAPI options&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPICleanupCredentials yes&lt;br /&gt;
 GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
=== Sur le serveur du LAMA ===&lt;br /&gt;
&lt;br /&gt;
 # kadmin -l&lt;br /&gt;
 kadmin&amp;gt; add -r host/d45.lama.univ-savoie.fr@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
 kadmin&amp;gt; ext_keytab -k /tmp/d45.keytab host/d45.lama.univ-savoie.fr&lt;br /&gt;
 kadmin&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
=== De nouveau sur la machine à Kerbériser ===&lt;br /&gt;
 # scp www.lama.univ-savoie.fr:/tmp/d45.keytab /etc/krb5.keytab&lt;br /&gt;
 # chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5561</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5561"/>
		<updated>2012-07-10T13:42:19Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Sur le client ===&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
 Host *&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
 [libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
 [realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
Pour chaque serveur SSH :&lt;br /&gt;
Dans /etc/ssh/sshd_config :&lt;br /&gt;
 # Kerberos options&lt;br /&gt;
 KerberosAuthentication yes&lt;br /&gt;
 KerberosOrLocalPasswd yes&lt;br /&gt;
 KerberosTicketCleanup yes&lt;br /&gt;
&lt;br /&gt;
 # GSSAPI options&lt;br /&gt;
 GSSAPIAuthentication yes&lt;br /&gt;
 GSSAPICleanupCredentials yes&lt;br /&gt;
 GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
Sur le serveur du LAMA :&lt;br /&gt;
 kadmin -l&lt;br /&gt;
 addprinc -r host/fqdn.de.la.machine@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
Puis copier le fichier /tmp/keytab.machine vers la machine:/etc/krb5.keytab&lt;br /&gt;
 chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5560</id>
		<title>SshAvecAfs</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=SshAvecAfs&amp;diff=5560"/>
		<updated>2012-07-10T13:40:26Z</updated>

		<summary type="html">&lt;p&gt;Hatat : Instructions pour configurer ssh et sshd avec Kerberos et AFS&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sur le client :&lt;br /&gt;
&lt;br /&gt;
Dans /etc/ssh/ssh_config, ajouter :&lt;br /&gt;
Host *&lt;br /&gt;
GSSAPIAuthentication yes&lt;br /&gt;
GSSAPIDelegateCredentials yes&lt;br /&gt;
&lt;br /&gt;
Dans /etc/krb5.conf, vérifier que le royaume est bien connu :&lt;br /&gt;
[libdefaults]&lt;br /&gt;
        default_realm = LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
        forwardable = true&lt;br /&gt;
[realms]&lt;br /&gt;
        LAMA.UNIV-SAVOIE.FR = {&lt;br /&gt;
                kdc = printers-lama.local.univ-savoie.fr&lt;br /&gt;
                admin_server = printers-lama.local.univ-savoie.fr&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
Pour chaque serveur SSH :&lt;br /&gt;
Dans /etc/ssh/sshd_config :&lt;br /&gt;
# Kerberos options&lt;br /&gt;
KerberosAuthentication yes&lt;br /&gt;
KerberosOrLocalPasswd yes&lt;br /&gt;
KerberosTicketCleanup yes&lt;br /&gt;
&lt;br /&gt;
# GSSAPI options&lt;br /&gt;
GSSAPIAuthentication yes&lt;br /&gt;
GSSAPICleanupCredentials yes&lt;br /&gt;
GSSAPIStrictAcceptorCheck no # ça c&#039;est super important&lt;br /&gt;
&lt;br /&gt;
Sur le serveur du LAMA :&lt;br /&gt;
kadmin -l&lt;br /&gt;
addprinc -r host/fqdn.de.la.machine@LAMA.UNIV-SAVOIE.FR&lt;br /&gt;
&lt;br /&gt;
Puis copier le fichier /tmp/keytab.machine vers la machine:/etc/krb5.keytab&lt;br /&gt;
chmod 600 /etc/krb5.keytab&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Documentation&amp;diff=4687</id>
		<title>Documentation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Documentation&amp;diff=4687"/>
		<updated>2010-01-26T18:04:44Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Problèmes connus sur le réseau LAMA */ Impression qui remarche&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Documentation pour les utilisateurs du réseau LAMA==&lt;br /&gt;
&lt;br /&gt;
[[ Utilisation des imprimantes ]]&lt;br /&gt;
&lt;br /&gt;
[[ Accès au sauvegarde périodique de votre compte ]]&lt;br /&gt;
&lt;br /&gt;
[[ Accès à vos fichiers à partir de Mac OS ]]&lt;br /&gt;
&lt;br /&gt;
[[ Accès à vos fichiers à partir de Windows ]]&lt;br /&gt;
&lt;br /&gt;
[http://www.lama.univ-savoie.fr/wiki/index.php/MUST Accès à la grille de calcul MUST]&lt;br /&gt;
&lt;br /&gt;
[[ Mathrice ]]&lt;br /&gt;
&lt;br /&gt;
[http://www.projet-plume.org/le-projet-description Projet PLUME : promotion du lociel libre]&lt;br /&gt;
&lt;br /&gt;
[[ Synchronisation des comptes : unison ]]&lt;br /&gt;
&lt;br /&gt;
[[ Conversion latex vers html  ]]&lt;br /&gt;
&lt;br /&gt;
[[ Machines au LAMA ]]&lt;br /&gt;
&lt;br /&gt;
[[ Utilisation de SVN ]]&lt;br /&gt;
&lt;br /&gt;
[[ Utilisation de la salle 115 ]]&lt;br /&gt;
&lt;br /&gt;
[[ Mise en ligne des calendriers ]]&lt;br /&gt;
&lt;br /&gt;
== Problèmes connus sur le réseau LAMA ==&lt;br /&gt;
&lt;br /&gt;
N&#039;hésitez pas à ajouter quelque chose dans cette section si vous rencontrez un problème. Les administrateurs du réseau reçoivent un mail automatiquement lorsque cette page est modifiée.&lt;br /&gt;
&lt;br /&gt;
- Les options (recto-verso,...) ne sont pas toujours transmises correctement aux imprimantes ...&lt;br /&gt;
en cours d&#039;investigation. Si vous n&#039;arrivez pas à faire autrement, un ssh sur www.lama.univ-savoie.fr &lt;br /&gt;
et l&#039;utilisation de la commande lpr permet de contourner ce problème.&lt;br /&gt;
&lt;br /&gt;
- &amp;lt;strike&amp;gt;Evince (visualisateur pdf et postscript par défaut sous gnome) ne permet pas d&#039;imprimer sur des serveurs cups distants (le bouton &amp;quot;imprimer&amp;quot; reste grisé). Solution : utiliser kghostview ou un autre visualisateur.&amp;lt;/strike&amp;gt; L&#039;impression fonctionne à nouveau depuis les applications Gnome.&lt;br /&gt;
&lt;br /&gt;
==Documentation pour les administrateurs du réseau LAMA==&lt;br /&gt;
&lt;br /&gt;
[[ Ouverture des comptes ]]&lt;br /&gt;
&lt;br /&gt;
[[ Liste des membres du labo sur le site ]] &lt;br /&gt;
&lt;br /&gt;
[[ Installation de ubuntu linux sur les postes clients ]]&lt;br /&gt;
&lt;br /&gt;
[[ Installation de Debian GNU-Linux sur les postes clients ]]&lt;br /&gt;
&lt;br /&gt;
[[ Organisation du serveur web www.lama.univ-savoie.fr ]]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4596</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4596"/>
		<updated>2009-12-11T11:06:53Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Sujet TP3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source],&lt;br /&gt;
#* [http://www.gnu.org/software/grub/manual/multiboot/multiboot.html Multiboot Specification] : SOS respecte la spécification Multiboot, qui dit comment un système d&#039;exploitation doit être chargé en mémoire par GRUB (ou tout autre chargeur respectant cette spécification).&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau].&lt;br /&gt;
# Ordonnancement :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp3.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp3.tar.gz code source].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4595</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4595"/>
		<updated>2009-12-11T10:17:59Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source],&lt;br /&gt;
#* [http://www.gnu.org/software/grub/manual/multiboot/multiboot.html Multiboot Specification] : SOS respecte la spécification Multiboot, qui dit comment un système d&#039;exploitation doit être chargé en mémoire par GRUB (ou tout autre chargeur respectant cette spécification).&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau].&lt;br /&gt;
# Ordonnancement :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp3.tar.gz code source].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4594</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4594"/>
		<updated>2009-12-11T10:17:46Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Archive TP3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source],&lt;br /&gt;
#* [http://www.gnu.org/software/grub/manual/multiboot/multiboot.html Multiboot Specification] : SOS respecte la spécification Multiboot, qui dit comment un système d&#039;exploitation doit être chargé en mémoire par GRUB (ou tout autre chargeur respectant cette spécification).&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau].&lt;br /&gt;
# Ordonnancement :&lt;br /&gt;
#* #* [http://www.lama.univ-savoie.fr/~hatat/sos-tp3.tar.gz code source].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4592</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4592"/>
		<updated>2009-12-10T08:38:07Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Lien Multiboot&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source],&lt;br /&gt;
#* [http://www.gnu.org/software/grub/manual/multiboot/multiboot.html Multiboot Specification] : SOS respecte la spécification Multiboot, qui dit comment un système d&#039;exploitation doit être chargé en mémoire par GRUB (ou tout autre chargeur respectant cette spécification).&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau].&lt;br /&gt;
# Ordonnancement.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4569</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4569"/>
		<updated>2009-12-07T14:24:23Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Ajout TP3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source].&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau].&lt;br /&gt;
# Ordonnancement.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4567</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4567"/>
		<updated>2009-12-04T12:54:15Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source].&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4566</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4566"/>
		<updated>2009-12-04T12:53:58Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Ajout du lien vers SOS article 5&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source].&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source],&lt;br /&gt;
#* Article [http://sos.enix.org/wiki-fr/upload/SOSDownload/sos-texte-art5.pdf Gestion de la mémoire virtuelle du noyau]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4559</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4559"/>
		<updated>2009-12-03T17:46:52Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Ajout du TP2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source].&lt;br /&gt;
# Gestion de la mémoire du noyau :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp2.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp2.tar.gz code source].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4554</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4554"/>
		<updated>2009-12-01T10:48:09Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS :&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz code source].&lt;br /&gt;
# Gestion de la mémoire du noyau.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4553</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4553"/>
		<updated>2009-11-27T12:19:06Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TP */ Sujet TP1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
# Découverte de SOS&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-tp1.pdf Sujet],&lt;br /&gt;
#* [http://www.lama.univ-savoie.fr/~hatat/sos-tp1.tar.gz Code source].&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4528</id>
		<title>INFO502 : Systèmes d&#039;exploitation</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=INFO502_:_Syst%C3%A8mes_d%27exploitation&amp;diff=4528"/>
		<updated>2009-11-17T16:10:45Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* TD */ Liens vers les sujets&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ce wiki est un complément de cours pour le cours « info-502 : systèmes d&#039;exploitation ». La participation au wiki est fortement encouragée.&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir modifier les pages, inscrivez-vous (lien en haut à droite) pour obtenir un login et mot de passe. (Choisissez un login du style &#039;&#039;PrenomNom&#039;&#039;...)&lt;br /&gt;
&lt;br /&gt;
Je vous conseille d&#039;aller lire [http://meta.wikimedia.org/wiki/Aide:Contenu ce guide] pour vous familiariser avec les wikis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice :&amp;lt;/u&amp;gt; si vous n&#039;en avez pas, créez-vous un compte et essayez de modifier cette page (correction de fautes d&#039;hortographe, rajout de détails, mise en page, ...)&lt;br /&gt;
&lt;br /&gt;
Vous pouvez aussi utiliser la page de discussion pour ... discuter. (Ou poser des questions, faire des commentaires etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
==Auteur du cours==&lt;br /&gt;
&lt;br /&gt;
===Nouvelles===&lt;br /&gt;
&lt;br /&gt;
===Supports===&lt;br /&gt;
&lt;br /&gt;
====TD====&lt;br /&gt;
&lt;br /&gt;
Sujets de TD :&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td1.pdf Ordonnancement],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td2.pdf Gestion de la mémoire],&lt;br /&gt;
# [http://www.lama.univ-savoie.fr/~hatat/cours/2009-info502-td3.pdf Systèmes de fichiers].&lt;br /&gt;
&lt;br /&gt;
====TP====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
==Repères historiques==&lt;br /&gt;
&lt;br /&gt;
Voici quelques évènements clés dans l&#039;histoire des systèmes d&#039;exploitation. Pour plus de détails, ou pour des compléments sur l&#039;histoire de l&#039;informatique, je vous renvoie sur Wikipedia : [http://en.wikipedia.org/wiki/History_of_operating_systems &amp;quot;History of operating systems&amp;quot;] et [http://en.wikipedia.org/wiki/History_of_computing &amp;quot;History of computing&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
Les premiers ordinateurs ne comportaient pas vraiment de système d&#039;exploitation : c&#039;étaient des opérateurs humains qui géraient tout. (C&#039;était juste après la seconde guerre mondiale, l faut savoir que les langages de programmation n&#039;existaient même pas...) La petite histoire (??) raconte qu&#039;à un moment, les processus pour l&#039;ordinateur de l&#039;université de Cambridge étaient accrochés sur une corde à linge et que c&#039;était la couleur des pinces à linges qui donnait la priorité. (??)&lt;br /&gt;
&lt;br /&gt;
Le passage à la notion de système d&#039;exploitation c&#039;est faite graduellement pour répondre à la complexité de plus en plus grande des ordinateurs et aux demandes des utilisateurs.&lt;br /&gt;
&lt;br /&gt;
Les premier systèmes d&#039;exploitation datent probablement de 1956. Ils permettaient simplement d&#039;exécuter un nouveau programme lorsque le précédent était terminé. Les ordinateurs d&#039;IBM de la famille System/360 ont ensuite eu toute une série de systèmes d&#039;exploitation plus ou moins similaires : OS/360, DOS/360 (rien à voir avec MS-DOS), TSS/360... C&#039;est à cette époque qu&#039;est apparu la notion de multiprogrammation (possibilité d&#039;avoir plusieurs processus entrelacés.)&lt;br /&gt;
C&#039;est également au début des années 60 qu&#039;on a commencé à voir des systèmes avec temps partagé : plusieurs utilisateurs pouvaient utiliser un ordinateur. Le système Multics a été, à ce niveau comme à d&#039;autres, assez révolutionnaire. Multics a été utilisé jusqu&#039;en 2000 !&lt;br /&gt;
&lt;br /&gt;
Multics n&#039;était par contre pas approprié pour les mini-ordinateurs où le nombre d&#039;utilisateur est relativement restreint. En 1969, Ken Thomson&lt;br /&gt;
a développé une variante simplifié de Multix : Unix...&lt;br /&gt;
&lt;br /&gt;
Ce n&#039;est qu&#039;un peu plus tard (1979) que la première version de DOS (86-DOS ou QDOS) apparaît. 86-DOS sera racheté par Microsoft un 1980...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liens et compléments :&#039;&#039;&#039;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Timeline_of_operating_systems Timeline of operating systems]&lt;br /&gt;
* généalogie des systèmes Unix : [http://www.levenez.com/unix/ Unix History]&lt;br /&gt;
* généalogie de Windows : [http://www.levenez.com/windows/ Windows History]&lt;br /&gt;
* généalogie des systèmes non-Unix : [http://www.oshistory.net/metadot/index.pl?id=2165 timeline of non-Unix operating systems]&lt;br /&gt;
&lt;br /&gt;
==Vue d&#039;ensemble==&lt;br /&gt;
&lt;br /&gt;
Ce cours reste assez généraliste et essaie de regarder les principales fonction d&#039;un système d&#039;exploitation. Les systèmes de type Unix (Linux) sera un exemple privilégié. À cause de leur complexité intrinsèque, les évolutions modernes (architectures multicoeur ou multiprocesseur, ...) seront en partie ignorée dans un premier temps.&lt;br /&gt;
&lt;br /&gt;
Les problèmes fins de communication entres processus ne seront que très peu abordés, car ils font l&#039;objet d&#039;un cours séparé (info604) pour la filière info.&lt;br /&gt;
&lt;br /&gt;
Nous allons suivre l&#039;ordre classique consistant à regarder :&lt;br /&gt;
# les processus&lt;br /&gt;
# la mémoire&lt;br /&gt;
# les entrées / sorties&lt;br /&gt;
&lt;br /&gt;
La fin du cours dépendra du temps restant...&lt;br /&gt;
&lt;br /&gt;
===Les processus===&lt;br /&gt;
&lt;br /&gt;
Un processus est simplement un programme « en exécution ». À tout instant, un ordinateur de bureau contemporain contient de nombreux processus qui doivent partager le (les) processeur(s) pour donner l&#039;impression qu&#039;ils s&#039;exécutent « en même temps ». Un des rôles du système d&#039;exploitation consiste à décider dans quel ordre les processus vont effectivement pouvoir utiliser le processus.&lt;br /&gt;
&lt;br /&gt;
===La mémoire===&lt;br /&gt;
&lt;br /&gt;
La mémoire est, comme le processeur, une ressource partagée par les différents processus. Il faut donc gérer la quantité de mémoire allouée et utilisée pour que les processus n&#039;aient pas à s&#039;occuper de ceci. Un des concepts fondamentaux est celui de mémoire virtuelle. Ceci permet d&#039;offrir un espace mémoire pour chacun des processus de manière transparente.&lt;br /&gt;
&lt;br /&gt;
===Les entrées / sorties===&lt;br /&gt;
&lt;br /&gt;
Un ordinateur n&#039;est pas (plus) un système indépendant du reste du monde : il interagit avec l&#039;extérieur à travers des périphériques d&#039;entrées/sorties (clavier / écran / souris / ...). La gestion de ces périphériques pose un ensemble de problèmes que nous aborderons brièvement...&lt;br /&gt;
&lt;br /&gt;
===...===&lt;br /&gt;
&lt;br /&gt;
Une fois ces notions vues, nous regarderons peut-être les problèmes de sécurité, de multimédia ou des architectures multiprocesseurs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Préliminaires==&lt;br /&gt;
&lt;br /&gt;
===Quoi ?===&lt;br /&gt;
&lt;br /&gt;
Les ordinateurs, ou plus simplement les micro contrôleurs sont des circuits électroniques avec une puce « processeur ». Le développement d&#039;applications n&#039;est pas facile si on se place au niveau électronique et que l&#039;on parle directement au CPU. Pour faciliter la vie des programmeurs, plusieurs couches d&#039;abstraction sont nécessaires. La première se place au niveau matériel et s&#039;occupe directement des problèmes électroniques ou de très bas niveau. Il s&#039;agit du &#039;&#039;firmware&#039;&#039;. Il répond par exemple aux questions comme :&lt;br /&gt;
* qu&#039;elle est l&#039;amplitude des signaux envoyés par l&#039;horloge ?&lt;br /&gt;
* est-ce que l&#039;UC possède un pipeline ?&lt;br /&gt;
* ...&lt;br /&gt;
Un firmware est donc forcement très lié au matériel sur lequel il tourne.&lt;br /&gt;
&lt;br /&gt;
La couche suivante est le système d&#039;exploitation à proprement parler.  Dans le cas que vous connaissez le mieux (ordinateur personnel), le système d&#039;exploitation fournit une interface pour :&lt;br /&gt;
* exécuter un programme&lt;br /&gt;
* exécuter plusieurs programmes « en même temps »&lt;br /&gt;
* gérer les ressources (temps processeur, mémoire disponible, entrées / sorties)&lt;br /&gt;
* les opérations sur les fichiers&lt;br /&gt;
* offrir des garanties de sécurité&lt;br /&gt;
&lt;br /&gt;
===Où ?===&lt;br /&gt;
&lt;br /&gt;
On trouve des systèmes d&#039;exploitation partout :&lt;br /&gt;
&lt;br /&gt;
* dans les ordinateurs personnels (Linux, BSD, MacOS, Solaris, Windows, ChromeOS (?))&lt;br /&gt;
* dans les PDA (PalmOS, ...)&lt;br /&gt;
* dans les téléphones portables (Android, OpenMoko,Symbian,)&lt;br /&gt;
* console de jeux&lt;br /&gt;
* lecteur MP3 (Rockbox, ...)&lt;br /&gt;
* les microcontroleurs « avancés »&lt;br /&gt;
&lt;br /&gt;
===Comment ?===&lt;br /&gt;
&lt;br /&gt;
====Langage de programmation====&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation se situe entre le firmware (très bas niveau) et l&#039;utilisateur. La nécessité d&#039;accéder à ces ressources de très bas niveau implique que les langages de haut niveaux (Java, Ada, Python, ...) ne sont pas du tout adaptés à l&#039;écriture des systèmes d&#039;exploitation.&lt;br /&gt;
Le langage le plus utilisé reste à ce jours le langage C : Linux, BSD, MacOS, Windows, ... sont tous écrits pour leur plus grande partie en C.&lt;br /&gt;
&lt;br /&gt;
Vous avez normalement un cours de C en parallèle, et les TPs utiliseront le langage C. (La référence sur le langage C reste à mon goût le livre de Kernighan et Ritchie : « the C Programming language ». (Disponible en francais à la BU sous le titre « Le langage C : norme Ansi ».) Il existe de nombreux autres livres / documents sur la programmation C comme le [http://www-clips.imag.fr/commun/bernard.cassagne/Introduction_ANSI_C.html polycopié de Bernard Cassagne « introduction au langage C »].&lt;br /&gt;
&lt;br /&gt;
Les premiers systèmes d&#039;exploitation étaient écrits directement en langage machine, ou bien en langage d&#039;assembleur ; et les systèmes actuels comportent encore quelques parties de très bas niveau en langage d&#039;assemblage...&lt;br /&gt;
&lt;br /&gt;
====Notion d&#039;appel système, norme POSIX====&lt;br /&gt;
&lt;br /&gt;
La programmation de haut niveau en C est assez différente de la programmation système. De nombreuses fonctions C utilisent en fait des « appels système », c&#039;est à dire des appels de fonctionnalités propres du système d&#039;exploitation. Les appels système typiques sont :&lt;br /&gt;
* les fonctions relatives aux fichiers (création, suppression, modification...)&lt;br /&gt;
* les fonctions relatives à la gestion de la mémoire&lt;br /&gt;
* les fonctions relatives aux processus (&amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
De nombreux système d&#039;exploitation proposent une interface [http://en.wikipedia.org/wiki/Posix POSIX] (« &#039;&#039;&#039;P&#039;&#039;&#039;ortable &#039;&#039;&#039;O&#039;&#039;&#039;perating &#039;&#039;&#039;S&#039;&#039;&#039;ystem &#039;&#039;&#039;I&#039;&#039;&#039;nterface for Uni&#039;&#039;&#039;x&#039;&#039;&#039; »). Cette norme définit entre autres un ensemble de fonctions pour utiliser les appels systèmes.&lt;br /&gt;
Le nombre de ces fonctions est relativement faible : une centaine ; et chacune correspond en gros à un appel système. Certaines de ces fonctions ne sont pas définies directement dans le système d&#039;exploitation, mais dans des librairies. Pour Linux, il s&#039;agit en général de la librairie Glibc (GNU C Library).&lt;br /&gt;
&lt;br /&gt;
Par exemple, la fonction &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt; (qui permet d&#039;ouvrir un fichier) correspond exactement à un appel système ; alors que la fonction &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; (qui permet d&#039;allouer dynamiquement de la mémoire dans le tas) peut générer plusieurs appels système (&amp;lt;tt&amp;gt;brk&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;sbrk&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les appels systèmes effectués par un programme sous Linux, vous pouvez utilisez l&#039;utilitaire &amp;lt;tt&amp;gt;strace&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;ltrace&amp;lt;/tt&amp;gt;. Par exemple, dans le shell :&lt;br /&gt;
  $ strace -e trace=file ls -l 2&amp;gt; trace&lt;br /&gt;
permet de récupérer tous les appels systèmes relatifs aux fichiers lors de l&#039;appel à &amp;lt;tt&amp;gt;ls -l&amp;lt;/tt&amp;gt;. La liste des appels système est redirigée dans le fichier &amp;lt;tt&amp;gt;trace&amp;lt;/tt&amp;gt; qui contiendra par exemple des lignes telles que&lt;br /&gt;
 lstat64(&amp;quot;Desktop&amp;quot;, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0&lt;br /&gt;
 lgetxattr(&amp;quot;Desktop&amp;quot;, &amp;quot;security.selinux&amp;quot;, 0x8cc08e0, 255) = -1 ENODATA (No data available)&lt;br /&gt;
dénotant ainsi un appel aux appels système &amp;lt;tt&amp;gt;lstat64&amp;lt;/tt&amp;gt; et &amp;lt;tt&amp;gt;lgetxattr&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
Les principaux systèmes compatibles POSIX sont :&lt;br /&gt;
* Linux&lt;br /&gt;
* BSD (et variantes)&lt;br /&gt;
* Mac OS X&lt;br /&gt;
* Solaris&lt;br /&gt;
&lt;br /&gt;
De nombreux appels systèmes sont disponibles directement (sans avoir besoin d&#039;écrire un programme C) à travers le shell. Exécuté dans un terminal, le shell permet, en première approximation, de passer directement des commandes au système d&#039;exploitation. (La norme POSIX définit également un ensemble de fonctions du shell. Il est donc relativement aisé de changer de système d&#039;exploitation tant qu&#039;on reste dans les systèmes compatibles POSIX.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows d&#039;un autre côté utilise l&#039;interface Win32 API, qui définit plusieurs milliers de fonctions. La plupart de ces fonctions peuvent utiliser plusieurs appels système...&lt;br /&gt;
&lt;br /&gt;
Les systèmes d&#039;exploitation qui utilisent l&#039;API Win32 sont :&lt;br /&gt;
* Windows, depuis Windows95.&lt;br /&gt;
&lt;br /&gt;
Il est possible d&#039;installer un environnement compatible POSIX sur une machine Windows grâce à Cygwin. (C&#039;est d&#039;ailleurs fortement conseillé si vous ne voulez pas installer une version de Linux ou BSD sur votre ordinateur personnel...)&lt;br /&gt;
&lt;br /&gt;
====Mode noyau / mode utilisateur====&lt;br /&gt;
&lt;br /&gt;
La partie fondamentale du système d&#039;exploitation est le &#039;&#039;noyau&#039;&#039; (&#039;&#039;kernel&#039;&#039; en anglais). C&#039;est la couche de plus bas niveau.&lt;br /&gt;
&lt;br /&gt;
Les fonctionnalités de très bas niveau offertes par le noyau peuvent facilement planter l&#039;ordinateur. Il faut donc une politique de restriction pour que tous les programmes ne puissent y accéder dans leur totalité. On parle de&lt;br /&gt;
* mode noyau&lt;br /&gt;
* mode utilisateur&lt;br /&gt;
&lt;br /&gt;
Dans le mode utilisateur, on ne peut accéder à ces fonctionnalités qu&#039;a travers les appels systèmes ; dans le mode noyau, on peut tout faire... Bien entendu, un appel système doit passer momentanément en mode noyau pour pouvoir exécuter les commandes pertinentes, puis il repasse automatiquement en mode utilisateur.&lt;br /&gt;
&lt;br /&gt;
La définition d&#039;un appel système pourrait donc être « fonctionnalité atomique nécessitant un passage en mode noyau ».&lt;br /&gt;
&lt;br /&gt;
====Noyau, noyau monolithique, micro-noyau====&lt;br /&gt;
&lt;br /&gt;
La partie principale du système d&#039;exploitation. C&#039;est lui qui gère les ressources, les entrées / sorties, la communication entre processus, ... Les deux architectures principales pour un noyau sont :&lt;br /&gt;
* noyau monolithique&lt;br /&gt;
* micro-noyau&lt;br /&gt;
La plupart des systèmes actuels sont basés sur un noyau monolithique (Linux, BSD, Mac OS X, Solaris, Windows).&lt;br /&gt;
&lt;br /&gt;
Les noyaux monolithiques sont parfois décrits comme « sans vraie structure » : une grosse soupe où cohabitent toutes les fonctionnalités du système d&#039;exploitation. L&#039;idée d&#039;avoir un système unique qui gère tout est effectivement peu attirante et peut poser quelques problèmes de génie logiciel...&lt;br /&gt;
Un noyau monolithique est donc la couche entre le matériel et les programmes utilisateurs. Pour éviter de compiler des noyaux énormes, les noyaux monolithiques actuels utilisent en plus la notion de &#039;&#039;module&#039;&#039;. Ce sont des morceaux du noyau qu&#039;on peut charger ou décharger au besoin. Si l&#039;interface est connue, ces modules peuvent éventuellement être en binaire, ce qui permet d&#039;utiliser des modules propriétaires avec un noyau libre.&lt;br /&gt;
Sous Linux, la commande&lt;br /&gt;
 $ lsmod&lt;br /&gt;
permet d&#039;obtenir la liste des modules chargés dans le noyau.&lt;br /&gt;
&lt;br /&gt;
Les micro-noyaux d&#039;un autre coté sont basés sur la remarque que seule une toute petite partie du noyau accède effectivement au matériel. Seule cette petite partie nécessite donc des privilèges et effectue des appels système. Le reste du système d&#039;exploitation peut être programmé en mode utilisateur, « au dessus » de cette partie. Par exemple, le micro noyau offrira la possibilité de charger un nouveau processus, mais l&#039;ordonnanceur (qui choisit quel processus devra être chargé) ne fera pas partie du micro-noyau. On parle parfois de &#039;&#039;services&#039;&#039; / &#039;&#039;serveurs&#039;&#039; au dessus du micro-noyau.&lt;br /&gt;
Ceci permet d&#039;avoir un noyau bas niveau beaucoup plus petit. Bien que ceci soit une bonne idée, et que les micro-noyaux puissent fournir de meilleurs garanties de sécurité, peu de noyaux sont effectivement des micro-noyaux. Un des problèmes est qu&#039;un tel micro-noyau est un peu plus lent que ses cousins monolithiques. La raison principale est que dans le cas d&#039;un micro-noyau, un appel système nécessite en fait des communications inter-processus.&lt;br /&gt;
Andrew Tanenbaum est un fervent défenseur des micro-noyaux.&lt;br /&gt;
&lt;br /&gt;
Une autre architecture possible est d&#039;utiliser des couches successives, chacune avec des privilèges réduits. Le système Multics avait cette architecture.&lt;br /&gt;
Par exemple, dans le système THE (1965), les couches étaient les suivantes :&lt;br /&gt;
# noyau bas niveau, multiprogrammation&lt;br /&gt;
# allocation de la mémoire pour les processus&lt;br /&gt;
# IPC (communication inter processus)&lt;br /&gt;
# entrées / sorties (buffer, etc.)&lt;br /&gt;
# programmes utilisateurs (compilation, exécution, ...)&lt;br /&gt;
# utilisateur (Dijkstra a annoté la description de cette couche par &#039;&#039;« not implemented by us »&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une dernière catégorie de noyau est la catégorie des machines virtuelles. Ces noyaux sont un peu à part, car il s&#039;agit d&#039;émuler un système d&#039;exploitation ou du matériel particulier à l&#039;intérieur d&#039;un autre système d&#039;exploitation ou matériel. Le mode noyau de la machine virtuelle est en fait dans le mode utilisateur du noyau original...&lt;br /&gt;
&lt;br /&gt;
==Les processus==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
Allez hop commençons par une petite définition du type wikipédia :&lt;br /&gt;
&lt;br /&gt;
Un processus (en anglais, process), en informatique, est défini par :&lt;br /&gt;
* un ensemble d&#039;instructions à exécuter (un programme) ;&lt;br /&gt;
* un espace mémoire pour les données de travail ;&lt;br /&gt;
* éventuellement, d&#039;autres ressources, comme des descripteurs de fichiers, des ports réseau, etc.&lt;br /&gt;
&lt;br /&gt;
Un ordinateur équipé d&#039;un système d&#039;exploitation à temps partagé est capable d&#039;exécuter plusieurs processus de façon « quasi- simultanée ». Par analogie avec les télécommunications, on nomme multiplexage (A. Tanenbaum parle de &#039;&#039;multiprogrammation&#039;&#039;) ce procédé. S&#039;il y a plusieurs processeurs, le système essaie de répartir les processus de manière équitable sur les processeurs disponibles.&lt;br /&gt;
&lt;br /&gt;
Le processus doit être imaginé comme quelque chose qui prend du temps, donc qui a un début et (parfois) une fin. De nombreux processus ne se terminent normalement jamais : système d&#039;exploitation, serveurs web, serveurs mail, ... D&#039;autres processus plus légers qui ne se terminent pas sont les &#039;&#039;daemon&#039;&#039; (acronyme &#039;&#039;a posteriori&#039;&#039; de &amp;quot;disk and execution monitor&amp;quot;) du monde Unix.&lt;br /&gt;
&lt;br /&gt;
Certains processus sont démarrés très tôt lors de la séquence de boot. Le système d&#039;exploitation est un tel processus. Sinon, les processus sont normalement démarrés grâce à un appel système à partir d&#039;un autre processus. L&#039;utilisateur peut par exemple demander explicitement un nouveau processus (sous POSIX, grâce à un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; puis &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;) ; mais la plupart du temps, il le fera à travers une application, par exemple en double-cliquant sur l&#039;icône d&#039;un programme dans l&#039;explorateur de fichiers.&lt;br /&gt;
&lt;br /&gt;
Le système d&#039;exploitation est chargé d&#039;allouer les ressources (mémoires, temps processeur, entrées/sorties) nécessaires aux processus et d&#039;assurer que le fonctionnement d&#039;un processus n&#039;interfère pas avec celui des autres (isolation).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pas sûr d&#039;avoir tout compris ? Ce n&#039;est pas grave, essayons autrement.&lt;br /&gt;
:&#039;&#039;&#039;Définition :&#039;&#039;&#039; un processus est un programme en train de s&#039;exécuter.&lt;br /&gt;
Cette définition implique en particulier que un programme (navigateur Firefox par exemple) peut correspondre à&lt;br /&gt;
* zéro processus si on ne l&#039;a pas lancé,&lt;br /&gt;
* un processus si on l&#039;a lancé,&lt;br /&gt;
* plusieurs processus si on l&#039;a lancé plusieurs fois.&lt;br /&gt;
(&#039;&#039;Remarque :&#039;&#039; pour un programme comme Firefox, il y a fort à parier que l&#039;exécution d&#039;une seule instance de Firefox génère de multiples sous-processus...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Que se passe-t-il quand je démarre une application?&lt;br /&gt;
&lt;br /&gt;
:L&#039;ordinateur à une nouvelle tâche à accomplir, les instructions correspondantes sont donc envoyées au processeur. Comme il a plusieurs choses à faire le choix des instructions à exécuter n&#039;est pas forcement simple. Il faut faire en sorte de partager le processeur entre les différentes tâches de manière équitable : c&#039;est la fameuse gestion des processus.&lt;br /&gt;
:Ceci permet de réaliser plusieurs activités en ~même temps~. Grâce à la gestion des processus on peut regarder un film (obtenu par des moyens tout à fait légaux cela va de soit), tout en jouant à la dame de pique.&lt;br /&gt;
:(et dire que certain(e)s affirment que l&#039;homme est mono tâche)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Plusieurs processus indépendants peuvent être &#039;&#039;actifs&#039;&#039; en même temps, mais sauf si l&#039;ordinateur possède suffisamment de processeurs, on ne peut pas les exécuter simultanément. L&#039;impression que plusieurs programmes s&#039;exécutent &#039;&#039;en même temps&#039;&#039; vient simplement du fait que le processeur alterne rapidement entre eux.&lt;br /&gt;
Comme le temps d&#039;exécution d&#039;une instruction par le processeur est très court, de l&#039;ordre de la nano-seconde, le processeur peut réaliser plusieurs centaines de millions d&#039;instructions par seconde. Ainsi, une tranche de temps de quelques fractions de seconde, partagée entre plusieurs processus, donne à l&#039;échelle macroscopique l&#039;illusion de la simultanéité.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;En résumé :&#039;&#039;&#039; un système d&#039;exploitation doit la plupart du temps traiter plusieurs tâches en même temps, et comme il n&#039;a, en général, qu&#039;un seul processeur, il devra contourner ce problème grâce à un pseudo-parallélisme. Il traite une tâche à la fois, s&#039;interrompt et passe à la suivante. La commutation de tâches étant très rapide, il donne l&#039;illusion d&#039;effectuer un traitement simultané.&lt;br /&gt;
&lt;br /&gt;
===La table des processus===&lt;br /&gt;
&lt;br /&gt;
L&#039;information sur les processus est conservé par le système dans une structure de données appelée &#039;&#039;table des processus&#039;&#039;. Cette table contient toutes les informations nécessaires à la gestion des processus : &lt;br /&gt;
* état du processus&lt;br /&gt;
* PID&lt;br /&gt;
* droits&lt;br /&gt;
* répertoire de travail&lt;br /&gt;
* pointeur vers la pile&lt;br /&gt;
* priorités&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Sous Linux, on peut accéder à ces informations à travers le système de fichiers virtuel &amp;quot;Procfs&amp;quot;. Il suffit d&#039;aller dans le répertoire &amp;lt;tt&amp;gt;/proc/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Création d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
Pour les système POSIX, la création d&#039;un processus est très simple : on utilise la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. En C, le prototype de la fonction se trouve dans le fichier d&#039;entêtes &amp;lt;tt&amp;gt;unistd.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cette fonction prend 0 argument et permet de faire la chose suivante : elle crée un nouveau processus qui est une copie conforme du processus appelant. La seule différence visible entre l&#039;ancien et le nouveau processus est que les processus ont un numéro (PID) différent. Pour le processus appelant, il peut obtenir le PID du nouveau processus en regardant la valeur de retour de &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt;. Pour le nouveau processus, cette valeur vaudra 0, et il devra utiliser la fonction &amp;lt;tt&amp;gt;getpid()&amp;lt;/tt&amp;gt; pour obtenir son numéro.&lt;br /&gt;
&lt;br /&gt;
Le processus appelant est appelé le &#039;&#039;père&#039;&#039; alors que le nouveau processus est appelé le &#039;&#039;fils&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Notez que l&#039;espace mémoire du processus est dupliqué plutôt que partagé. Ceci veut dire que les processus ne peuvent pas communiquer en utilisant leur variables... Par contre, les descripteurs de fichiers du fils sont hérités directement de ceux du père ; ils peuvent donc essayer de communiquer en passant par ces fichiers. (Mais cela pose de nombreux problèmes de synchronisation.)&lt;br /&gt;
&lt;br /&gt;
Voici par exemple un petit programme C qui lance un processus fils:&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
 &lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
 &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return(0);&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
Après compilation, voici un exemple d&#039;exécution du programme résultant :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8248 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8249).&lt;br /&gt;
&lt;br /&gt;
Voici un autre exemple d&#039;exécution :&lt;br /&gt;
 $ ./pere_fils&lt;br /&gt;
 &amp;gt; Le processus 8269 démarre...&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le père (pid du fils = 8270).&lt;br /&gt;
  &amp;gt;&amp;gt; Je suis le fils.&lt;br /&gt;
&lt;br /&gt;
Notez que les numéros sont différents, et que l&#039;ordre d&#039;affichage n&#039;est pas le même. Cela vient de l&#039;ordonnancement des deux processus qui peut différer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La technique consistant à faire&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
montre que malgré le fait que les processus soient identiques à l&#039;origine, on peut faire beaucoup de chose.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Remarque :&#039;&#039;&#039; &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; n&#039;est pas directement un appel système, mais une fonction qui utilise l&#039;appel système &amp;lt;tt&amp;gt;clone()&amp;lt;/tt&amp;gt;. Cet appel système ne fait pas partie de la norme POSIX...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La deuxième technique utilisée dans les systèmes POSIX consiste à utiliser &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; pour dupliquer le processus, puis à complètement remplacer le fils par un nouveau processus. La fonction correspondante est la fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; :&lt;br /&gt;
 pid = fork();&lt;br /&gt;
 if (pid) { /* le père */&lt;br /&gt;
   ...&lt;br /&gt;
 } else { /* le fils */&lt;br /&gt;
   execv(&amp;quot;/usr/bin/...&amp;quot;, argv);&lt;br /&gt;
   ...&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;tt&amp;gt;execv&amp;lt;/tt&amp;gt; prend 2 arguments : une chaîne contenant le chemin d&#039;accès à un programme, et un tableau d&#039;arguments à donner au programme. (C&#039;est un peu plus compliqué que ça : le premier élément du tableau est le nom du programme, et le tableau doit se terminer par un pointeur NULL.)&lt;br /&gt;
&lt;br /&gt;
Une dernière fonction importante est la fonction &amp;lt;tt&amp;gt;wait(pid)&amp;lt;/tt&amp;gt; qui permet à un processus d&#039;attendre l&#039;arrêt du processus &amp;lt;tt&amp;gt;pid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 -- ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#039;API WIN32 possède de nombreuses fonctions avec des fonctionnalités similaires. Par exemple, la fonction [http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx &amp;lt;tt&amp;gt;CreateProcess&amp;lt;/tt&amp;gt;] permet de créer un nouveau processus (comme un &amp;lt;tt&amp;gt;fork&amp;lt;/tt&amp;gt; suivi d&#039;un &amp;lt;tt&amp;gt;exec&amp;lt;/tt&amp;gt;), mais elle nécessite ... 10 arguments !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
Un autre moyen de créer des processus est d&#039;utiliser des &#039;processus légers&#039; appelés Thread. Ces processus légers partage seulement une partie de la mémoire, ce qui en pratique est plus rapide pour simuler un parallélisme. On passe alors par une autre fonction. Sous GNU/Linux, lors de l&#039;écriture d&#039;un programme écrit en C il faut utiliser la bibliothèque pthread.h et lors de la compilation, faire un lien vers celle ci, en utilisant le paramètre -lpthread.&lt;br /&gt;
&lt;br /&gt;
====Arborescence des processus dans les systèmes POSIX====&lt;br /&gt;
&lt;br /&gt;
Nous avons vu que la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt; permet de créer un processus fils. Le père connaît le PID de son fils : il lui est donné par la fonction &amp;lt;tt&amp;gt;fork()&amp;lt;/tt&amp;gt;. Comme le fils peut lui même créer des processus fils, on obtient rapidement une arborescence de processus.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez visualiser cette arborescence à partir d&#039;un terminal avec la commande &amp;lt;tt&amp;gt;pstree&amp;lt;/tt&amp;gt; (l&#039;option &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; permet de demander l&#039;affichage des PID)&lt;br /&gt;
 $ pstree -p&lt;br /&gt;
 init(1)─┬─acpid(25425)&lt;br /&gt;
         ├─atd(14365)&lt;br /&gt;
         ├─console-kit-dae(3632)─┬─{console-kit-dae}(3633)&lt;br /&gt;
         │                       ├─{console-kit-dae}(3641)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─cron(14315)&lt;br /&gt;
         ├─dbus-daemon(15590)&lt;br /&gt;
         ├─dbus-daemon(3511)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─getty(4095)&lt;br /&gt;
         ├─getty(4096)&lt;br /&gt;
         ├─getty(4097)&lt;br /&gt;
         ├─getty(4098)&lt;br /&gt;
         ├─getty(4099)&lt;br /&gt;
         ├─gpm(3528)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─kded4(15769)&lt;br /&gt;
         ├─kdeinit4(15766)───klauncher(15767)&lt;br /&gt;
         ├─kdm(15564)─┬─Xorg(15566)&lt;br /&gt;
         │            └─kdm(15573)───sh(15608)─┬─conky(15751)&lt;br /&gt;
         │                                     ├─fluxbox(15703)───firefox-bin(6063)─┬─{firefox-bin}(6064)&lt;br /&gt;
         │                                     │                                    ├─{firefox-bin}(6065)&lt;br /&gt;
 ...&lt;br /&gt;
         │                                     ├─ssh-agent(15698)&lt;br /&gt;
         │                                     ├─unclutter(15742)&lt;br /&gt;
         │                                     ├─wicd-client(15749)&lt;br /&gt;
         │                                     └─xscreensaver(15683)&lt;br /&gt;
 ...&lt;br /&gt;
         ├─rsyslogd(6850)─┬─{rsyslogd}(6140)&lt;br /&gt;
         │                └─{rsyslogd}(6141)&lt;br /&gt;
         ├─screen(4427)─┬─bash(4428)───pstree(9307)&lt;br /&gt;
         │              ├─bash(4429)───man(7952)───pager(7965)&lt;br /&gt;
         │              ├─bash(4430)───vi(30568)&lt;br /&gt;
         │              ├─bash(18395)───vi(28512)&lt;br /&gt;
         │              └─mutt(8763)&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
Le processus &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; est l&#039;ancêtre de tout les processus, il a toujours 1 comme PID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; sous Windows, les processus ne sont pas organisé en arborescence...&lt;br /&gt;
&lt;br /&gt;
====Mort d&#039;un processus dans un système POSIX====&lt;br /&gt;
&lt;br /&gt;
Un processus peut se terminer pour plusieurs raisons :&lt;br /&gt;
* volontairement, grâce à la fonction &amp;lt;tt&amp;gt;exit()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;ExitProcess()&amp;lt;/tt&amp;gt; (Windows),&lt;br /&gt;
* à cause d&#039;une erreur,&lt;br /&gt;
* en recevant un signal d&#039;un autre processus, grâce à la fonction &amp;lt;tt&amp;gt;kill()&amp;lt;/tt&amp;gt; (POSIX) ou &amp;lt;tt&amp;gt;TerminateProcess()&amp;lt;/tt&amp;gt; (Windows).&lt;br /&gt;
&lt;br /&gt;
Lorsqu&#039;un processus se termine, plusieurs choix sont possibles :&lt;br /&gt;
* que fait-on de ses fils ?&lt;br /&gt;
* que fait-on de son père ?&lt;br /&gt;
&lt;br /&gt;
Linux fait la chose suivante : quand un processus s&#039;arrête,&lt;br /&gt;
* tous ces fils s&#039;arrêtent,&lt;br /&gt;
* son père reçoit un signal le prévenant que son fils vient de mourir.&lt;br /&gt;
&lt;br /&gt;
Pour que le père puisse recevoir le signal correspondant, il faut qu&#039;il utilise la fonction &amp;lt;tt&amp;gt;wait()&amp;lt;/tt&amp;gt; ou &amp;lt;tt&amp;gt;waitpid()&amp;lt;/tt&amp;gt;. Tant que le parent existe et qu&#039;il n&#039;a pas reçu le signal disant qu&#039;un de ces fils est mort, le processus fils n&#039;est pas entièrement supprimé : il devient un &#039;&#039;zombie&#039;&#039;. (Il n&#039;occupe plus vraiment de place en mémoire, mais le système garde juste suffisamment d&#039;information pour pouvoir prévenir le père si celui ci demande l&#039;état du fils.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; les processus Windows ne sont pas organisés sous forme d&#039;arborescence. Chaque processus peut surveiller l&#039;état d&#039;un autre processus, s&#039;il connaît son PID. Il n&#039;y a donc pas de notion de processus &#039;&#039;zombie&#039;&#039; sous Windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voici un petit programme C qui crée un processus fils, ne fait rien pendant 20 secondes, puis demande l&#039;état de son fils :&lt;br /&gt;
 #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 int main() {&lt;br /&gt;
   int pid ;&lt;br /&gt;
   int pid_fils ;&lt;br /&gt;
   int w;&lt;br /&gt;
 &lt;br /&gt;
   pid = getpid();&lt;br /&gt;
   printf(&amp;quot;&amp;gt; Le processus %i démarre...\n&amp;quot;, pid);&lt;br /&gt;
  &lt;br /&gt;
   pid_fils = fork();&lt;br /&gt;
 &lt;br /&gt;
   if(pid_fils) {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père (pid du fils = %i).\n&amp;quot;,pid_fils);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et j&#039;attends un peu.\n&amp;quot;);&lt;br /&gt;
     sleep(20);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le père et je demande l&#039;état de mon fils.\n&amp;quot;);&lt;br /&gt;
     wait(&amp;amp;w);&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort (signal %i).\n&amp;quot;, w);&lt;br /&gt;
     while(1) sleep(1);&lt;br /&gt;
   } else {&lt;br /&gt;
     printf(&amp;quot; &amp;gt;&amp;gt; Je suis le fils.\n&amp;quot;);&lt;br /&gt;
     while (1) sleep(1);&lt;br /&gt;
     exit(0);&lt;br /&gt;
   }&lt;br /&gt;
   return(0);&lt;br /&gt;
 }&lt;br /&gt;
Si on tue le processus fils pendant que le père ne fait rien, le processus fils devient un zombie. Dès que le père fait le &amp;lt;tt&amp;gt;wait&amp;lt;/tt&amp;gt;, il reçoit la valeur du signal qui a terminé le processus et le zombie disparaît.&lt;br /&gt;
&lt;br /&gt;
Si on ne tue pas le processus fils, le père n&#039;exécutera jamais le &amp;lt;tt&amp;gt;printf(&amp;quot; &amp;gt;&amp;gt; Mon fils est mort...);&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque :&#039;&#039;&#039; dans un système POSIX, lorsqu&#039;un processus meurt, ses fils deviennent &#039;&#039;orphelins&#039;&#039;. Il continuent leur exécution mais sont adopté par &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt; (PID : 1). Dans certains cas lorsque le processus est arrêté, il envoie explicitement un signal &amp;lt;tt&amp;gt;SIGTERM&amp;lt;/tt&amp;gt; pour tuer ses processus fils. C&#039;est par exemple ce qui arrive lorsqu&#039;on lance des application à partir d&#039;un terminal et que l&#039;on quitte le terminal en question...&lt;br /&gt;
&lt;br /&gt;
===États d&#039;un processus===&lt;br /&gt;
&lt;br /&gt;
On peut imaginer un SE dans lequel les processus pourraient être dans trois états :&lt;br /&gt;
* en cours d&#039;exécution,&lt;br /&gt;
*bloqué : il attend un événement extérieur pour pouvoir continuer (par exemple une ressource; lorsque la ressource est disponible, il passe à l&#039;état &amp;quot;prêt&amp;quot;)&lt;br /&gt;
*prêt : suspendu provisoirement pour permettre l&#039;exécution d&#039;un autre processus.&lt;br /&gt;
&lt;br /&gt;
Dans un système avec un unique processeur, au plus un processus peut se trouver dans l&#039;état &#039;&#039;en cours d&#039;exécution&#039;&#039;. Par contre, il peut y avoir de nombreux processus dans l&#039;état &#039;&#039;bloqué&#039;&#039; ou dans l&#039;état &#039;&#039;prêt&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Un processus peut passer d&#039;un état à l&#039;autre :&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;bloqué&#039;&#039; lorsqu&#039;une ressource n&#039;est pas disponible (entrées / sortie par exemple),&lt;br /&gt;
# de &#039;&#039;bloqué&#039;&#039; à &#039;&#039;prêt&#039;&#039; si la ressource ayant provoqué le blocage devient disponible,&lt;br /&gt;
# de &#039;&#039;en exécution&#039;&#039; à &#039;&#039;prêt&#039;&#039; si le système décide de suspendre l&#039;exécution du processus,&lt;br /&gt;
# de &#039;&#039;prêt&#039;&#039; à &#039;&#039;en exécution&#039;&#039; si le système décide de lancer l&#039;exécution du processus.&lt;br /&gt;
&lt;br /&gt;
On peut résumer ceci par le graphe de transitions suivant :&lt;br /&gt;
&lt;br /&gt;
[[Image:Diagrammedétatdunprocessus.png]]&lt;br /&gt;
&lt;br /&gt;
Les transition manquantes ne sont pas possible directement mais doivent passer par des transition intermédiaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On peut ajouter 2 états :&lt;br /&gt;
* &#039;&#039;nouveau&#039;&#039; pour un processus qui vient d&#039;être créé,&lt;br /&gt;
* &#039;&#039;terminé&#039;&#039; pour un processus qui vient de se terminé.&lt;br /&gt;
&lt;br /&gt;
Dans les systèmes type &#039;&#039;ordinateur de bureau&#039;&#039;, le passage de &#039;&#039;nouveau&#039;&#039; à &#039;&#039;prêt&#039;&#039; est automatique mais dans des systèmes temps réel, un processus peut parfois attendre dans cet état.&lt;br /&gt;
&lt;br /&gt;
L&#039;état &#039;&#039;terminé&#039;&#039; est en général passager. Par exemple, lorsqu&#039;un processus terminé est un zombie, le processus n&#039;est conservé que dans la table des processus. La mémoire utilisé par le processus est libérée. La question de savoir si ceci est véritablement un état du processus est donc essentiellement une question de vocabulaire.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; ajouter les états &#039;&#039;nouveau&#039;&#039; et &#039;&#039;terminé&#039;&#039; et les transitions correspondantes au graphe précédent. Identifiez des situations provoquant les transitions possibles entre états.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ordonnancement des processus===&lt;br /&gt;
&lt;br /&gt;
Nous avons vu qu&#039;il pouvait y avoir de nombreux processus dans la table de processus (environ 150 sur mon ordinateur en ce moment même). Parmi ces processus, un seul (sur une machine à un processeur) peut se trouver dans l&#039;état &#039;&#039;en exécution&#039;&#039;. C&#039;est au système d&#039;exploitation de décider qui, à un moment donnée, doit se trouver dans cet état. La partie du système faisant ceci s&#039;appelle &#039;&#039;ordonnanceur&#039;&#039; (ou &#039;&#039;scheduler&#039;&#039; en anglais).&lt;br /&gt;
En utilisant le contenu de la table des processus et éventuellement d&#039;autres information, ordonnanceur doit donc gérer les transition entre états de tous les processus, et envoyer l&#039;information nécessaire aux composants adéquat du noyau.&lt;br /&gt;
&lt;br /&gt;
Comme d&#039;habitude, l&#039;ordonnanceur doit faire des compromis entre :&lt;br /&gt;
* la vitesse,&lt;br /&gt;
* l&#039;utilisation de la mémoire,&lt;br /&gt;
* l&#039;optimalité de la solution proposée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remarque : &#039;&#039;&#039; l&#039;ordonnanceur est lui même un processus (ou un morceau de processus dans le cas des noyaux monolithiques).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement non préemptif====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FIFO.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme d&#039;ordonnancement le plus facile est probablement celui de type &#039;&#039;FIFO&#039;&#039; : premier arrivé, premier servi. Autrement dit, on préempte premier processus arrivé, et on l&#039;exécute jusqu&#039;à la fin. La seul structure de donnée est donc simplement une &#039;&#039;file&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plus court temps d&#039;exécution.&#039;&#039;&#039;&lt;br /&gt;
Dans certain cas, on peut prévoir a l&#039;avance le temps processeur dont aura besoin un processus pour s&#039;exécuter. On peut alors choisir le processus le plus court et l&#039;exécuter en premier. Ceci a en général tendance à diminuer le temps d&#039;attente moyen d&#039;un processus ; mais si des processus courts sont crées régulièrement, on peut assister à une &#039;&#039;famine&#039;&#039; : un processus peut ne jamais s&#039;exécuter.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; trouver une suite de processus qui provoque une famine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ces deux exemples sont acceptables pour un &#039;&#039;traitement par lots&#039;&#039; (batch) par exemple pour des calculs numériques. Ils ne sont par contre pas du tout adaptés pour un ordinateur personnel ou un système temps réels. (Pas de &#039;&#039;multiprogrammation&#039;&#039;.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ordonnancement préemptif====&lt;br /&gt;
&lt;br /&gt;
Pour pouvoir donner l&#039;illusion de simultanéité, les processus sont en général exécutés par tranches de temps spécifiées à l&#039;avance (&#039;&#039;time slice&#039;&#039; en anglais). Au bout de ce temps, le noyau reçoit une interruption et examine les processus. Il peut décider de continuer le processus courant, ou bien le remplacer par un autre processus. on parle de préemption.&lt;br /&gt;
&lt;br /&gt;
Windows 3.1 ou MacOS 9 étaient des systèmes &#039;&#039;collaboratifs&#039;&#039; car les processus devaient explicitement laisser la main aux autres processus. Tous les systèmes d&#039;exploitation modernes sont maintenant préemptifs. On parle maintenant de système préemptif lorsque la préemption peut s&#039;effectuer même sur des processus en mode noyau.&lt;br /&gt;
On parle parfois de noyau préemptible lorsque que les opérations en mode noyau sont elle même préemptibles. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet.&#039;&#039;&#039;&lt;br /&gt;
L&#039;algorithme le plus simple est probablement celui du tourniquet (&#039;&#039;round Robin&#039;&#039; en anglais). C&#039;est une variante de l&#039;algorithme FIFO vu plus haut, mais qui préempte le processus courant au bout d&#039;un moment. Si ce processus est encore en exécution, on le remet à la fin de la file des processus.&lt;br /&gt;
&lt;br /&gt;
Le temps imparti à chaque processus ne doit pas être trop court (sinon, le changement de contexte prend trop de temps par rapport à l&#039;exécution des processus) ni trop long (sinon, on perd l&#039;illusion de parallélisme, et un processus bloqué risque d&#039;occuper le processeur pendant trop longtemps).&lt;br /&gt;
&lt;br /&gt;
Voici ce qu&#039;on peut trouver dans le livre &amp;quot;Understanding the Linux kernel&amp;quot; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cite&amp;gt;&lt;br /&gt;
The choice of quantum duration is always a compromise. The rule of thumb adopted by Linux is: choose a duration as long as possible, while keeping good system response time.&lt;br /&gt;
&amp;lt;/cite&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(extrait du chapitre [http://oreilly.com/catalog/linuxkernel/chapter/ch10.html &amp;quot;Process Scheduling&amp;quot;]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tourniquet avec priorité.&#039;&#039;&#039;&lt;br /&gt;
Tous les processus ne naissent pas égaux : certains ont une importance plus élevée (les processus systèmes par exemple). Dans un cas comme le précédent, tous les processus ont le même statut...&lt;br /&gt;
Pour corriger ce problème, on utilise parfois un algorithme similaire, mais on choisit le premier processus de priorité la plus élevé possible. Plutôt que de parcourir la file à sa rechercher, on utilise en fait plusieurs files : une pour chaque priorité.&lt;br /&gt;
&lt;br /&gt;
Il faut faire attention car les processus de priorité basse risquent de ne jamais être exécutés (famine)... Par exemple, on peut diminuer petit à petit la priorité des processus qu&#039;on exécute...&lt;br /&gt;
&lt;br /&gt;
Une autre solution pour gérer les priorité en évitant certaines famines est d&#039;exécuter toutes les files, mais pas en proportion égale. Par exemple, on choisit un processus dans les piles de priorité 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, ... De cette manière, les processus de la première file sont exécutés 2 fois plus de fois que ceux de la file 2, et 4 fois plus de fois que ceux de la file 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;exercice :&amp;lt;/u&amp;gt; donnez un algorithme pour générer la suite précédente pour un nombre donné de files. Il faut que la file &#039;&#039;i&#039;&#039; soit utilisée 2 fois plus souvent que la pile &#039;&#039;i+1&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Répartition garantie.&#039;&#039;&#039;&lt;br /&gt;
Chaque tache reçoit la même proportion du processeur, et chaque utilisateur reçoit la même proportion également.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tirage aléatoire.&#039;&#039;&#039;&lt;br /&gt;
À chaque étape, on tire un &amp;quot;billet&amp;quot; au hasard, et le processus qui a le &amp;quot;billet gagnant&amp;quot; s&#039;exécute.&lt;br /&gt;
&lt;br /&gt;
Principe de priorité : Les processus qui ont été définit comme prioritaire on plus de &amp;quot;billet&amp;quot; à leur nom et ont donc plus de chance d&#039;être tiré.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB : POSIX définit une commande &amp;quot;nice&amp;quot; qui permet e donner à un processus un priorité plus faible (et par conséquent, nice -x augmente cette priorité). Il est évident que tout le monde ne doit pas pouvoir utiliser cette commande, il vaut mieux que l&#039;administrateur se réserve ce droit&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ordonnancement équitable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==La mémoire==&lt;br /&gt;
&lt;br /&gt;
===Introduction===&lt;br /&gt;
&lt;br /&gt;
RAM = Random Acces Memory. C&#039;est ce que l&#039;on appelle couramment la mémoire vive, elle peut être modifié à l&#039;infini et sert à stocker temporairement les fichiers que l&#039;ordinateur exécute.&lt;br /&gt;
&lt;br /&gt;
ROM = Read Only Memory. On l&#039;appelle aussi mémoire fixe ou mémoire morte, dès que l&#039;on enregistre, le contenu d&#039;une mémoire ROM ne peut pas être modifié (ex: un CD-ROM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gestion de la mémoire : &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Lors du boot du PC, le système est chargé en mémoire.&lt;br /&gt;
Tout processus créé est aussi chargé dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
Lorsque l&#039;on créé uns seul processus, il est plus pratique de le charger en &amp;quot;bas&amp;quot; de la mémoire, à partir de la première case de l&#039;espace mémoire. Puis les nouveaux processus peuvent être charger par dessus. Ainsi la machine comprend où commence l&#039;espace mémoire.&lt;br /&gt;
&lt;br /&gt;
Problèmes :&lt;br /&gt;
1 - l&#039;espace d&#039;adressage ne commence pas à 0;&lt;br /&gt;
2 - un processus peut demander dynamiquement de la mémoire;&lt;br /&gt;
3 - avec un accès direct, un processus peut faire &amp;quot;planter&amp;quot; un autre.&lt;br /&gt;
&lt;br /&gt;
==&amp;gt; Il faut avoir une couche d&#039;abstraction au-dessus de la mémoire physique.&lt;br /&gt;
&lt;br /&gt;
===Espaces d&#039;adressage===&lt;br /&gt;
&lt;br /&gt;
Et si l&#039;on créait des espaces d&#039;adressage distincts pour chaque processus ?&lt;br /&gt;
Par exemple : chaque processus utilise des adresse de 0 à n de la mémoire, on converti alors ces adresses en adresses physiques.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Certains des premiers processeurs avaient deux registres supérieurs :&lt;br /&gt;
&lt;br /&gt;
- une Base =&amp;gt; adresse physique du début de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
- une Limite =&amp;gt; adresse physique de fin de l&#039;espace d&#039;adressage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par exemple, lors de l&#039;exécution d&#039;un processus l&#039;accès à une case &amp;quot;a&amp;quot; se transforme en l&#039;accès à la Base+a et un test pour vérifier que : a+Base &amp;lt; Limite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Malgré tout, ceci ne résout pas les problèmes liés au fait que des processus sont créés et disparaissent, réclament ou libèrent de la mémoire.&lt;br /&gt;
&lt;br /&gt;
===Va-et-vient (swapping)===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
Et si pour gérer tout cela on utilisait une mémoire auxiliaire (disque), pour stocker l&#039;état de la mémoire de processus.&lt;br /&gt;
&lt;br /&gt;
La mémoire vue par les processus ne correspond pas à la mémoire physique. À un instant donné, certains processus peuvent se retrouver sur le disque (dans le SWAP).&lt;br /&gt;
&lt;br /&gt;
Quand un processus apparait, on lui cherche un morceau d&#039;espace libre dans la mémoire.&lt;br /&gt;
&lt;br /&gt;
====gestion de la mémoire====&lt;br /&gt;
&lt;br /&gt;
* tableau de bits&lt;br /&gt;
* liste chaînée&lt;br /&gt;
&lt;br /&gt;
====Allocation====&lt;br /&gt;
&lt;br /&gt;
* first fit&lt;br /&gt;
* next fit&lt;br /&gt;
* best fit&lt;br /&gt;
* worst fit&lt;br /&gt;
&lt;br /&gt;
===Mémoire virtuelle===&lt;br /&gt;
&lt;br /&gt;
====Idée====&lt;br /&gt;
&lt;br /&gt;
====Pagination====&lt;br /&gt;
&lt;br /&gt;
====Traduction des adresses====&lt;br /&gt;
&lt;br /&gt;
====Table des pages====&lt;br /&gt;
&lt;br /&gt;
====Table inversée====&lt;br /&gt;
&lt;br /&gt;
====Remplacement des pages====&lt;br /&gt;
&lt;br /&gt;
==Les entrées / sorties==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Références==&lt;br /&gt;
&lt;br /&gt;
* le livre « Systèmes d&#039;exploitation » de Andrew Tanenbaum est disponible à la BU&lt;br /&gt;
* la page du [http://sos.enix.org/fr/PagePrincipale projet SOS]&lt;br /&gt;
* la [http://www.opengroup.org/onlinepubs/009695399/nfindex.html norme POSIX:2004]&lt;br /&gt;
* l&#039;[http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx API win32]&lt;br /&gt;
* [http://www.lemis.com/grog/Documentation/Lions/index.php Commentary on the Sixth Edition UNIX Operating System]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Langage_et_concepts_cat%C3%A9goriques_pour_les_math%C3%A9matiques_et_l%E2%80%99informatique&amp;diff=3959</id>
		<title>Langage et concepts catégoriques pour les mathématiques et l’informatique</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Langage_et_concepts_cat%C3%A9goriques_pour_les_math%C3%A9matiques_et_l%E2%80%99informatique&amp;diff=3959"/>
		<updated>2009-03-13T16:00:37Z</updated>

		<summary type="html">&lt;p&gt;Hatat : Pif paf la définition&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a wiki for a course at the MSTII &amp;quot;École doctorale&amp;quot; of Grenoble.&lt;br /&gt;
&lt;br /&gt;
Students are encouraged to participate by extending the wiki, adding proofs, corrections for exercices etc. To be able to modify the wiki, you need to register (upper right corner). Please use your real name...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===News===&lt;br /&gt;
&lt;br /&gt;
Courses are on wednesdays morning, 9&#039;00 to 12&#039;00 in room F218 at the &amp;quot;UFR IMAG&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* first course on the 25th of February: categories, functors, natural transformations.&lt;br /&gt;
* March 4. : monads, adjunctions.&lt;br /&gt;
* March 11. : limits and colimits.&lt;br /&gt;
&lt;br /&gt;
==Basic Concepts==&lt;br /&gt;
&lt;br /&gt;
===Categories===&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A concrete category is given by:&lt;br /&gt;
* a collection of sets &#039;&#039;with structure&#039;&#039;,&lt;br /&gt;
* for any pair of such sets, a set of &#039;&#039;morphisms&#039;&#039; preserving the structure.&lt;br /&gt;
Morphisms should compose, and the identity should be a morphism.}}&lt;br /&gt;
&lt;br /&gt;
This definition is a little informal, but here are some examples:&lt;br /&gt;
* &#039;&#039;&#039;Grp&#039;&#039;&#039;: groups and group morphisms&lt;br /&gt;
* &#039;&#039;&#039;Top&#039;&#039;&#039;: topological spaces and continuous functions&lt;br /&gt;
* &#039;&#039;&#039;Ring&#039;&#039;&#039;: rings and rings morphisms&lt;br /&gt;
* &#039;&#039;&#039;Vect&#039;&#039;&#039;: vectors spaces and linear maps&lt;br /&gt;
* &#039;&#039;&#039;CPO&#039;&#039;&#039;: CPOs and continuous functions&lt;br /&gt;
* ...&lt;br /&gt;
* &#039;&#039;&#039;Set&#039;&#039;&#039;: sets and functions (&#039;&#039;&#039;ie&#039;&#039;&#039; sets with no structures, and arbitrary functions)&lt;br /&gt;
&lt;br /&gt;
Generalizing the definition, we obtain the official definition of category:&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; is given by:&lt;br /&gt;
* a collection &amp;lt;math&amp;gt;\mathcal{C}_o&amp;lt;/math&amp;gt; of &#039;&#039;objects&#039;&#039;,  (notation: &amp;lt;math&amp;gt;A,B,C,X,Y,...&amp;lt;/math&amp;gt;)&lt;br /&gt;
* for each pair &amp;lt;math&amp;gt;A,B&amp;lt;/math&amp;gt; of objects, a collection &amp;lt;math&amp;gt;\mathcal{C}[A,B]&amp;lt;/math&amp;gt; of &#039;&#039;morphisms from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;&#039;,  (notation &amp;lt;math&amp;gt; f : A\to B&amp;lt;/math&amp;gt;)&lt;br /&gt;
* for any object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, a special morphism &amp;lt;math&amp;gt;i_A : A\to A&amp;lt;/math&amp;gt;&lt;br /&gt;
* for all objects &amp;lt;math&amp;gt;A,B,C&amp;lt;/math&amp;gt;, a composition &amp;lt;math&amp;gt;\circ : \mathcal{C}[B,C] \times \mathcal{C}[A,B] \to \mathcal{C}[A,C]&amp;lt;/math&amp;gt;,&lt;br /&gt;
such that:&lt;br /&gt;
* &amp;lt;math&amp;gt;f \in \mathcal{C}[A,B] \implies f\circ i_A = i_B\circ f = f&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;f\circ(g\circ h) = (f\circ g)\circ h&amp;lt;/math&amp;gt; whenever it makes sense.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
All concrete categories are categories, and here are some examples that are not obviously concrete:&lt;br /&gt;
* &#039;&#039;&#039;Graph&#039;&#039;&#039;: graphs and graph morphisms&lt;br /&gt;
* &#039;&#039;&#039;Rel&#039;&#039;&#039;: sets and relations&lt;br /&gt;
* &#039;&#039;&#039;Set×Set&#039;&#039;&#039;: pairs of sets, pairs of functions&lt;br /&gt;
* &#039;&#039;&#039;Set&amp;lt;math&amp;gt;^{op}&amp;lt;/math&amp;gt;&#039;&#039;&#039;: opposite of &#039;&#039;&#039;Set&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;, whenever (&#039;&#039;&#039;P&#039;&#039;&#039;,&amp;lt;) is a preorder (at most one morphism between objects)&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039;, whenever (&#039;&#039;&#039;M&#039;&#039;&#039;,e,×) is a monoid (a single object)&lt;br /&gt;
&lt;br /&gt;
We sometimes write &amp;lt;math&amp;gt;gf&amp;lt;/math&amp;gt; instead of &amp;lt;math&amp;gt;g \circ f&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a given category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, there are analogues of the notions of injective and surjective functions in &#039;&#039;&#039;Set&#039;&#039;&#039;. We will see that on concrete categories, they are actually slightly more general. The idea of injectivity gives rise to &#039;&#039;monomorphisms&#039;&#039;, and surjectivity gives rise to &#039;&#039;epimorphisms&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
&lt;br /&gt;
A morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; is a &#039;&#039;monomorphism&#039;&#039; iff for all object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; and morphisms &amp;lt;math&amp;gt;g,h \colon C \to A&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;fg = fh&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;g = h&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The morphism &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; is an &#039;&#039;epimorphism&#039;&#039; when it is a monomorphism in &amp;lt;math&amp;gt;\mathcal{C}^{op}&amp;lt;/math&amp;gt;. Explicitly, when for all object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; and morphisms &amp;lt;math&amp;gt;g,h \colon B \to C&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;gf = hf&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;g = h&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
  isomorphism&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
# Prove that in &#039;&#039;&#039;Set&#039;&#039;&#039;, epic is equivalent to surjective and monic is equivalent to injective.&lt;br /&gt;
# Prove the same thing in &#039;&#039;&#039;Ab&#039;&#039;&#039;, the category of commutative groups. (One thing is not obvious.)&lt;br /&gt;
# Prove the same thing in &#039;&#039;&#039;Grp&#039;&#039;&#039;, the category of (non necessarily commutative) groups. (One thing is not obvious at all.)&lt;br /&gt;
# Prove that &amp;lt;math&amp;gt;i : \mathbf{Z} \to \mathbf{Q}&amp;lt;/math&amp;gt; is an epimorphism in the category of rings with multiplicative neutral. (Note that it is not surjective.)&lt;br /&gt;
# In &#039;&#039;&#039;Set&#039;&#039;&#039;, we saw that &#039;&#039;f&#039;&#039; is a monic iff &amp;lt;math&amp;gt;\forall x,y : 1 \to A, f\circ x = f\circ y \implies x=y&amp;lt;/math&amp;gt;, where 1 is any singleton set. Can you find a set &#039;&#039;C&#039;&#039; such that &#039;&#039;f&#039;&#039; is epic iff &amp;lt;math&amp;gt;\forall p,q : B \to C, p\circ f = j\circ f \implies p=q&amp;lt;/math&amp;gt;?&lt;br /&gt;
# In &#039;&#039;&#039;Group&#039;&#039;&#039;, can you find an object playing a role similar to 1, &#039;&#039;ie&#039;&#039; a group &#039;&#039;G&#039;&#039; s.t. &#039;&#039;f&#039;&#039; is monic iff &amp;lt;math&amp;gt;\forall x,y : G \to A, f\circ x = f\circ y \implies x=y&amp;lt;/math&amp;gt;. (We saw that we cannot use the singleton group ({e},e,×) to do that...)&lt;br /&gt;
&lt;br /&gt;
===Functors===&lt;br /&gt;
&lt;br /&gt;
Informally, a functor is a map between two categories which somehow preserves the structure of categories (namely, composition).&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; from a category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to a category &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt;, noted &amp;lt;math&amp;gt;F \colon \mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;, is given by:&lt;br /&gt;
* a map which sends every object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to an object &amp;lt;math&amp;gt;FA&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* a map which sends every morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, to a morphism &amp;lt;math&amp;gt;Ff&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}[FA, FB]&amp;lt;/math&amp;gt;,&lt;br /&gt;
such that:&lt;br /&gt;
* &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; preserves identities, i.e., &amp;lt;math&amp;gt;F(id_A) = id_{FA}&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; preserves composition: &amp;lt;math&amp;gt;F(f \circ g) = F(f) \circ F(g)&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
# Take a functor &amp;lt;math&amp;gt;F \colon \mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;f, g, h&amp;lt;/math&amp;gt; three morphisms in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, and &amp;lt;math&amp;gt;f&#039; = Ff&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g&#039; = Fg&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;h&#039; = Fh&amp;lt;/math&amp;gt;. When &amp;lt;math&amp;gt;h&#039; = f&#039; \circ g&#039;&amp;lt;/math&amp;gt;, can we say something interesting about &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;?&lt;br /&gt;
# Do functors preserve monomorphisms? Do functors preserve epimorphisms?&lt;br /&gt;
# Let &#039;&#039;F&#039;&#039; be a functor and &#039;&#039;F(f) = g&#039;&#039;, if &#039;&#039;g&#039;&#039; is a mono (resp. epi), is &#039;&#039;f&#039;&#039; a mono (resp. epi)?&lt;br /&gt;
If not, try to find some simple and natural condition on the functor to make that true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
# No, since &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; may not even compose! This is the case when &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;A \to B&amp;lt;/math&amp;gt;, and &amp;lt;math&amp;gt;g \colon C \to D&amp;lt;/math&amp;gt;, with &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; collapsing &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (i.e., &amp;lt;math&amp;gt;FA = FD&amp;lt;/math&amp;gt;).&lt;br /&gt;
# Functors in general do not preserve mono- nor epimorphisms. We build a counter-example for monomorphisms. Let &amp;lt;math&amp;gt;\mathbf{2}&amp;lt;/math&amp;gt; be the category with two objects &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt;, and exactly one morphism &amp;lt;math&amp;gt;m \colon \star \to \bullet&amp;lt;/math&amp;gt;. This is a preorder, so &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; is monic. Now take &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; with two objects &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt;, exactly one morphism &amp;lt;math&amp;gt;m \colon \star \to \bullet&amp;lt;/math&amp;gt;, and one extra morphism &amp;lt;math&amp;gt;n \colon \star \to \star&amp;lt;/math&amp;gt;, different from the identity. Because of &amp;lt;math&amp;gt;n \neq id_\star&amp;lt;/math&amp;gt;, yet &amp;lt;math&amp;gt;m \circ n = m \circ id&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; is not monic in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;. The functor which sends &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathbf{2}&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, does not preserve monomorphisms.&lt;br /&gt;
# In general, the answer is (again) no. For monos, take for example the functor &amp;lt;math&amp;gt;\mathcal{C} \to \mathbf{2}&amp;lt;/math&amp;gt; which sends &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; to the identity. Yet, when &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is &#039;&#039;faithful&#039;&#039;, then &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; is monic (or epic).&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is faithful when, for any two morphisms &amp;lt;math&amp;gt;f, g&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Ff = Fg&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;f=g&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is injective on morphisms).&lt;br /&gt;
}}&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is full when, for any two objects &amp;lt;math&amp;gt;A, B&amp;lt;/math&amp;gt;, if &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; is a morphism &amp;lt;math&amp;gt;FA \to FB&amp;lt;/math&amp;gt;, then there exists &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;Ff = g&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is surjective on morphisms).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Find an &amp;quot;interesting&amp;quot; functor from &#039;&#039;&#039;Set&#039;&#039;&#039; to &#039;&#039;&#039;Group&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
Let &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; be the functor which sends:&lt;br /&gt;
* every set &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; to the free group generated by &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* every function &amp;lt;math&amp;gt;f \colon X \to Y&amp;lt;/math&amp;gt; to a group morphism defined by: &amp;lt;math&amp;gt;Ff(x_1^{\alpha_1}\times\dots\times x_k^{\alpha_k})=f(x_1)^{\alpha_1} \times \dots \times f(x_k)^{\alpha_k}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; is a locally small category and &#039;&#039;A&#039;&#039; one of its objects, let &amp;lt;math&amp;gt;Y_A : X \mapsto \mathcal{C}[X,A]&amp;lt;/math&amp;gt;. Show that this operation from objects of &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to sets can be extended into a contravariant functor &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to &#039;&#039;&#039;Set&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
Let &amp;lt;math&amp;gt;f\colon X \to Y&amp;lt;/math&amp;gt; be a morphism in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;Y_A(f)&amp;lt;/math&amp;gt; is expected to be a function from the set &amp;lt;math&amp;gt;\mathcal{C}[Y, A]&amp;lt;/math&amp;gt; to the set &amp;lt;math&amp;gt;\mathcal{C}[X, A]&amp;lt;/math&amp;gt;. We can take, for any morphism &amp;lt;math&amp;gt;m \in \mathcal{C}[Y,A]&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;Y_A(f)(m) = m \circ f&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This extends &amp;lt;math&amp;gt;Y_A&amp;lt;/math&amp;gt; to a contravariant functor, since &amp;lt;math&amp;gt;Y_A(id_X) = id_{\mathcal{C}[X, A]}&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;Y_A(f \circ g)(m) = m \circ (f \circ g) = (m \circ f) \circ g = (Y_A(g) \circ Y_A(f))(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Natural Transformations===&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
Let &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; be two functors &amp;lt;math&amp;gt;\mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;. A natural transformation &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; from &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; is given by:&lt;br /&gt;
* a morphism &amp;lt;math&amp;gt;\alpha_A \colon FA \to GA&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt; for every object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;,&lt;br /&gt;
* such that, for any morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;Gf \circ \alpha_A = \alpha_B \circ Ff&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;P(X)&amp;lt;/math&amp;gt; is the set of permutation of a (finite) set &#039;&#039;X&#039;&#039;; and &amp;lt;math&amp;gt;L(X)&amp;lt;/math&amp;gt; the set of its linear orderings, we have &amp;lt;math&amp;gt;\#(L(X)) = \#(L(X)) = n!&amp;lt;/math&amp;gt; where &amp;lt;math&amp;gt;n = \#(X)&amp;lt;/math&amp;gt;. Thus, there is a bijection (iso in &#039;&#039;&#039;Set&#039;&#039;&#039;) between &#039;&#039;P(X)&#039;&#039; and &#039;&#039;L(X)&#039;&#039;.&lt;br /&gt;
# Show that we can extend &#039;&#039;P&#039;&#039; and &#039;&#039;L&#039;&#039; to functors from &#039;&#039;&#039;B&#039;&#039;&#039; to &#039;&#039;&#039;Set&#039;&#039;&#039;, where &#039;&#039;&#039;B&#039;&#039;&#039; is the category of finite sets and bijections,&lt;br /&gt;
# Show that there can be no natural transformation from &#039;&#039;P&#039;&#039; to &#039;&#039;L&#039;&#039;,&lt;br /&gt;
# Conclude that there is no natural isomorphism between &#039;&#039;P&#039;&#039; and &#039;&#039;L&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Adjunctions==&lt;br /&gt;
&lt;br /&gt;
===About Limits and Colimits===&lt;br /&gt;
&lt;br /&gt;
One of the main thrusts of category theory is to define concepts by&lt;br /&gt;
their properties rather than by explicit construction. In general this&lt;br /&gt;
is just called abstraction, but in good cases, concepts are&lt;br /&gt;
&#039;&#039;defined&#039;&#039; by their properties, at least canonically if not uniquely.&lt;br /&gt;
&lt;br /&gt;
The chief example of this is binary products in &#039;&#039;&#039;Set&#039;&#039;&#039;.  The&lt;br /&gt;
product &amp;lt;math&amp;gt;A \times B&amp;lt;/math&amp;gt; of two sets &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is generally thought of as the set of pairs &amp;lt;math&amp;gt; (x,&lt;br /&gt;
y) &amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;x \in A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;y \in B&amp;lt;/math&amp;gt;.  But&lt;br /&gt;
strictly speaking, or rather set-theoretically speaking, one has to&lt;br /&gt;
construct it by cautious use of the axioms of Zermelo-Fraenkel set&lt;br /&gt;
theory.&lt;br /&gt;
&lt;br /&gt;
Instead, in any category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, for any objects&lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; categorists put: &lt;br /&gt;
&lt;br /&gt;
{{Definition | A&lt;br /&gt;
&#039;&#039;product&#039;&#039; of &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is an object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt;&lt;br /&gt;
with arrows&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{\pi_1} C \xrightarrow{\pi_2} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
such that for any object &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; and arrows&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{f} D \xrightarrow{g} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
there exists a unique arrow &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; making the diagram&lt;br /&gt;
[[Image:prod.png|center|Universal property of product]]&lt;br /&gt;
commute, i.e., &amp;lt;math&amp;gt;\pi_1 \circ h = f&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\pi_2 \circ h = g&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
The standard constructions in &#039;&#039;&#039;Set&#039;&#039;&#039; all have this property, and&lt;br /&gt;
all the non-standard ones you can think of also do, e.g., the set of&lt;br /&gt;
pairs &amp;lt;math&amp;gt; (\emptyset, x, y) &amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;x \in A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;y&lt;br /&gt;
\in B&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Conversely, any set with this property is as good as any other&lt;br /&gt;
construction of &amp;lt;math&amp;gt;A \times B&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Products are determined &#039;&#039;canonically&#039;&#039; by this property&lt;br /&gt;
property. We will give a more precise meaning to this in later&lt;br /&gt;
lectures; for now we just state:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lemma.&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For any other product &amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{p} E \xrightarrow{q} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; of &lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, there is a unique isomorphism pair &amp;lt;math&amp;gt; (r, s) &amp;lt;/math&amp;gt; &lt;br /&gt;
such that the diagrams&lt;br /&gt;
&lt;br /&gt;
[[Image:prod-iso.png|upright=2]] and &lt;br /&gt;
[[Image:prod-iso-2.png|upright=2]]&lt;br /&gt;
&lt;br /&gt;
commute.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===First examples and definition===&lt;br /&gt;
&lt;br /&gt;
====So-called &#039;&#039;free&#039;&#039; constructions in algebra: monoid, group, etc====&lt;br /&gt;
====Their universal property, the underlying functor====&lt;br /&gt;
====The isomorphism between hom-sets====&lt;br /&gt;
====Its naturality====&lt;br /&gt;
====Definition====&lt;br /&gt;
====On to the definition with &amp;lt;math&amp;gt;\eta&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt;====&lt;br /&gt;
&lt;br /&gt;
===The simplicity behind definitions:2-categories and adjunctions therein===&lt;br /&gt;
&lt;br /&gt;
====Definition of 2-categories====&lt;br /&gt;
====String diagrams====&lt;br /&gt;
====&#039;&#039;&#039;CAT&#039;&#039;&#039; as a 2-category====&lt;br /&gt;
====Adjunctions in a 2-category====&lt;br /&gt;
&lt;br /&gt;
===Other basic examples===&lt;br /&gt;
&lt;br /&gt;
====Discussion: any syntax defines the free something==== The issue of &lt;br /&gt;
variable binding.&lt;br /&gt;
====Adjunction between partial orders = Galois connection====&lt;br /&gt;
====&amp;lt;math&amp;gt;\times&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\Rightarrow&amp;lt;/math&amp;gt; in logic====&lt;br /&gt;
====Sets/graphs and categories====&lt;br /&gt;
&lt;br /&gt;
===Monads and resolutions===&lt;br /&gt;
&lt;br /&gt;
====Definition of a monad====&lt;br /&gt;
====String diagrams====&lt;br /&gt;
====Every adjunction yields a monad====&lt;br /&gt;
====Example of monoids again: resolutions====&lt;br /&gt;
&lt;br /&gt;
===Monadic adjunctions===&lt;br /&gt;
&lt;br /&gt;
====The category of resolutions====&lt;br /&gt;
====Eilenberg-Moore is terminal====&lt;br /&gt;
====Kleisli is initial====&lt;br /&gt;
====Monadic adjunctions====&lt;br /&gt;
====Algebraic theories====&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
&lt;br /&gt;
====Composing adjunctions====&lt;br /&gt;
====Preservation of limits/colimits====&lt;br /&gt;
====Freyd&#039;s existence theorem====&lt;br /&gt;
====Beck&#039;s monadicity theorem====&lt;br /&gt;
&lt;br /&gt;
==Limites and Colimits==&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; Cartesian product.&lt;br /&gt;
&lt;br /&gt;
{{ Definition | Binary product.}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;The product of X and Y, if it exists, is unique up to isomorphism.&#039;&#039; (with proof)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples.&#039;&#039;&#039; Set, Grp, Ab, Part.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples.&#039;&#039;&#039; Preorder, Subset(E), Prop with entailment.&lt;br /&gt;
&lt;br /&gt;
{{ Definition | Diagram. Cone. Limit.}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; Limits in Set.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples.&#039;&#039;&#039; Shape of diagrams for products, pullbacks, equalizers.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; Monos as pullbacks.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;The limit of a diagram d, if it exists, is unique up to isomorphism.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;A category with &amp;quot;all&amp;quot; products and equalizers has &amp;quot;all&amp;quot; limits.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;A category with a terminal object and all binary products and all equalizers has all finite limits.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Colimits===&lt;br /&gt;
&lt;br /&gt;
{{ Definition | Cocone. Colimit.}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples.&#039;&#039;&#039; Sums in Set, Grp, Ab.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples.&#039;&#039;&#039; Shape of diagrams for sums, initial objects, pushouts, coequalizers.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; Epis as pushouts.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;The colimit of a diagram d, if it exists, is unique up to isomorphism.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; The most general unifier (of two terms) is a coequalizer in the &amp;quot;category of substitutions&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;A category with &amp;quot;all&amp;quot; sums and coequalizers has &amp;quot;all&amp;quot; colimits.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;A category with an initial object and all binary sums and all coequalizers has all finite colimits.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Limits, colimits and adjunctions===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Theorem.&#039;&#039;&#039; &#039;&#039;A right adjoint preserves limits. A left adjoint preserves colimits.&#039;&#039; (with proof of existence)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; The adjunction between Set and Grp&lt;br /&gt;
&lt;br /&gt;
===Sums and products===&lt;br /&gt;
&lt;br /&gt;
A category is &#039;&#039;distributive&#039;&#039; if the canonical map from AxB+AxC to Ax(B+C) is an isomorphism.&lt;br /&gt;
&lt;br /&gt;
A category is &#039;&#039;extensive&#039;&#039; if the canonical functor + from C/A x C/B to C/(A+B) is an equivalence. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example.&#039;&#039;&#039; &amp;quot;if..then..else..&amp;quot; from B=1+1 and extensivity.&lt;br /&gt;
 &lt;br /&gt;
==Course Complements, references==&lt;br /&gt;
&lt;br /&gt;
One of the best books about category theory is&lt;br /&gt;
* Saunder MacLane, &#039;&#039;&amp;quot;Categories for the Working Mathematician&amp;quot;&#039;&#039;.&lt;br /&gt;
It is a little &amp;quot;dry&amp;quot;, in the sense that learning categories from it is not the easiest task on earth, but it still is one of the best references.&lt;br /&gt;
&lt;br /&gt;
I haven&#039;t really read it carefully, but here is [http://en.wikipedia.org/wiki/Category_theory what Wikipedia has to say on category theory].&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Langage_et_concepts_cat%C3%A9goriques_pour_les_math%C3%A9matiques_et_l%E2%80%99informatique&amp;diff=3944</id>
		<title>Langage et concepts catégoriques pour les mathématiques et l’informatique</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Langage_et_concepts_cat%C3%A9goriques_pour_les_math%C3%A9matiques_et_l%E2%80%99informatique&amp;diff=3944"/>
		<updated>2009-03-10T14:59:06Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Natural Transformations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a wiki for a course at the MSTII &amp;quot;École doctorale&amp;quot; of Grenoble.&lt;br /&gt;
&lt;br /&gt;
Students are encouraged to participate by extending the wiki, adding proofs, corrections for exercices etc. To be able to modify the wiki, you need to register (upper right corner). Please use your real name...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===News===&lt;br /&gt;
&lt;br /&gt;
Courses are on wednesdays morning, 9&#039;00 to 12&#039;00 in room F218 at the &amp;quot;UFR IMAG&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* first course on the 25th of February: categories, functors, natural transformations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Basic Concepts==&lt;br /&gt;
&lt;br /&gt;
===Categories===&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A concrete category is given by:&lt;br /&gt;
* a collection of sets &#039;&#039;with structure&#039;&#039;,&lt;br /&gt;
* for any pair of such sets, a set of &#039;&#039;morphisms&#039;&#039; preserving the structure.&lt;br /&gt;
Morphisms should compose, and the identity should be a morphism.}}&lt;br /&gt;
&lt;br /&gt;
This definition is a little informal, but here are some examples:&lt;br /&gt;
* &#039;&#039;&#039;Grp&#039;&#039;&#039;: groups and group morphisms&lt;br /&gt;
* &#039;&#039;&#039;Top&#039;&#039;&#039;: topological spaces and continuous functions&lt;br /&gt;
* &#039;&#039;&#039;Ring&#039;&#039;&#039;: rings and rings morphisms&lt;br /&gt;
* &#039;&#039;&#039;Vect&#039;&#039;&#039;: vectors spaces and linear maps&lt;br /&gt;
* &#039;&#039;&#039;CPO&#039;&#039;&#039;: CPOs and continuous functions&lt;br /&gt;
* ...&lt;br /&gt;
* &#039;&#039;&#039;Set&#039;&#039;&#039;: sets and functions (&#039;&#039;&#039;ie&#039;&#039;&#039; sets with no structures, and arbitrary functions)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Generalizing the definition, we obtain the official definition of category:&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; is given by:&lt;br /&gt;
* a collection &amp;lt;math&amp;gt;\mathcal{C}_o&amp;lt;/math&amp;gt; of &#039;&#039;objects&#039;&#039;,  (notation: &amp;lt;math&amp;gt;A,B,C,X,Y,...&amp;lt;/math&amp;gt;)&lt;br /&gt;
* for each pair &amp;lt;math&amp;gt;A,B&amp;lt;/math&amp;gt; of objects, a collection &amp;lt;math&amp;gt;\mathcal{C}[A,B]&amp;lt;/math&amp;gt; of &#039;&#039;morphisms from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;&#039;,  (notation &amp;lt;math&amp;gt; f : A\to B&amp;lt;/math&amp;gt;)&lt;br /&gt;
* for any object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, a special morphism &amp;lt;math&amp;gt;i_A : A\to A&amp;lt;/math&amp;gt;&lt;br /&gt;
* for all objects &amp;lt;math&amp;gt;A,B,C&amp;lt;/math&amp;gt;, a composition &amp;lt;math&amp;gt;\circ : \mathcal{C}[B,C] \times \mathcal{C}[A,B] \to \mathcal{C}[A,C]&amp;lt;/math&amp;gt;,&lt;br /&gt;
such that:&lt;br /&gt;
* &amp;lt;math&amp;gt;f \in \mathcal{C}[A,B] \implies f\circ i_A = i_B\circ f = f&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;f\circ(g\circ h) = (f\circ g)\circ h&amp;lt;/math&amp;gt; whenever it makes sense.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
All concrete categories are categories, and here are some examples that are not obviously concrete:&lt;br /&gt;
* &#039;&#039;&#039;Graph&#039;&#039;&#039;: graphs and graph morphisms&lt;br /&gt;
* &#039;&#039;&#039;Rel&#039;&#039;&#039;: sets and relations&lt;br /&gt;
* &#039;&#039;&#039;Set×Set&#039;&#039;&#039;: pairs of sets, pairs of functions&lt;br /&gt;
* &#039;&#039;&#039;Set&amp;lt;math&amp;gt;^{op}&amp;lt;/math&amp;gt;&#039;&#039;&#039;: opposite of &#039;&#039;&#039;Set&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;, whenever (&#039;&#039;&#039;P&#039;&#039;&#039;,&amp;lt;) is a preorder (at most one morphism between objects)&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039;, whenever (&#039;&#039;&#039;M&#039;&#039;&#039;,e,×) is a monoid (a single object)&lt;br /&gt;
&lt;br /&gt;
We sometimes write &amp;lt;math&amp;gt;gf&amp;lt;/math&amp;gt; instead of &amp;lt;math&amp;gt;g \circ f&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a given category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, there are analogues of the notions of injective and surjective functions in &#039;&#039;&#039;Set&#039;&#039;&#039;. We will see that on concrete categories, they are actually slightly more general. The idea of injectivity gives rise to &#039;&#039;monomorphisms&#039;&#039;, and surjectivity gives rise to &#039;&#039;epimorphisms&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
&lt;br /&gt;
A morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; is a &#039;&#039;monomorphism&#039;&#039; iff for all object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; and morphisms &amp;lt;math&amp;gt;g,h \colon C \to A&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;fg = fh&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;g = h&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The morphism &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; is an &#039;&#039;epimorphism&#039;&#039; when it is a monomorphism in &amp;lt;math&amp;gt;\mathcal{C}^{op}&amp;lt;/math&amp;gt;. Explicitly, when for all object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; and morphisms &amp;lt;math&amp;gt;g,h \colon B \to C&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;gf = hf&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;g = h&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
  isomorphism&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
# Prove that in &#039;&#039;&#039;Set&#039;&#039;&#039;, epic is equivalent to surjective and monic is equivalent to injective.&lt;br /&gt;
# Prove the same thing in &#039;&#039;&#039;Ab&#039;&#039;&#039;, the category of commutative groups. (One thing is not obvious.)&lt;br /&gt;
# Prove the same thing in &#039;&#039;&#039;Grp&#039;&#039;&#039;, the category of (non necessarily commutative) groups. (One thing is not obvious at all.)&lt;br /&gt;
# Prove that &amp;lt;math&amp;gt;i : \mathbf{Z} \to \mathbf{Q}&amp;lt;/math&amp;gt; is an epimorphism in the category of rings with multiplicative neutral. (Note that it is not surjective.)&lt;br /&gt;
# In &#039;&#039;&#039;Set&#039;&#039;&#039;, we saw that &#039;&#039;f&#039;&#039; is a monic iff &amp;lt;math&amp;gt;\forall x,y : 1 \to A, f\circ x = f\circ y \implies x=y&amp;lt;/math&amp;gt;, where 1 is any singleton set. Can you find a set &#039;&#039;C&#039;&#039; such that &#039;&#039;f&#039;&#039; is epic iff &amp;lt;math&amp;gt;\forall p,q : B \to C, p\circ f = j\circ f \implies p=q&amp;lt;/math&amp;gt;?&lt;br /&gt;
# In &#039;&#039;&#039;Group&#039;&#039;&#039;, can you find an object playing a role similar to 1, &#039;&#039;ie&#039;&#039; a group &#039;&#039;G&#039;&#039; s.t. &#039;&#039;f&#039;&#039; is monic iff &amp;lt;math&amp;gt;\forall x,y : G \to A, f\circ x = f\circ y \implies x=y&amp;lt;/math&amp;gt;. (We saw that we cannot use the singleton group ({e},e,×) to do that...)&lt;br /&gt;
&lt;br /&gt;
===Functors===&lt;br /&gt;
&lt;br /&gt;
Informally, a functor is a map between two categories which somehow preserves the structure of categories (namely, composition).&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; from a category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to a category &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt;, noted &amp;lt;math&amp;gt;F \colon \mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;, is given by:&lt;br /&gt;
* a map which sends every object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to an object &amp;lt;math&amp;gt;FA&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* a map which sends every morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, to a morphism &amp;lt;math&amp;gt;Ff&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}[FA, FB]&amp;lt;/math&amp;gt;,&lt;br /&gt;
such that:&lt;br /&gt;
* &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; preserves identities, i.e., &amp;lt;math&amp;gt;F(id_A) = id_{FA}&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; preserves composition: &amp;lt;math&amp;gt;F(f \circ g) = F(f) \circ F(g)&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
# Take a functor &amp;lt;math&amp;gt;F \colon \mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;f, g, h&amp;lt;/math&amp;gt; three morphisms in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, and &amp;lt;math&amp;gt;f&#039; = Ff&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g&#039; = Fg&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;h&#039; = Fh&amp;lt;/math&amp;gt;. When &amp;lt;math&amp;gt;h&#039; = f&#039; \circ g&#039;&amp;lt;/math&amp;gt;, can we say something interesting about &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;?&lt;br /&gt;
# Do functors preserve monomorphisms? Do functors preserve epimorphisms?&lt;br /&gt;
# Let &#039;&#039;F&#039;&#039; be a functor and &#039;&#039;F(f) = g&#039;&#039;, if &#039;&#039;g&#039;&#039; is a mono (resp. epi), is &#039;&#039;f&#039;&#039; a mono (resp. epi)?&lt;br /&gt;
If not, try to find some simple and natural condition on the functor to make that true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
# No, since &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; may not even compose! This is the case when &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;A \to B&amp;lt;/math&amp;gt;, and &amp;lt;math&amp;gt;g \colon C \to D&amp;lt;/math&amp;gt;, with &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; collapsing &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (i.e., &amp;lt;math&amp;gt;FA = FD&amp;lt;/math&amp;gt;).&lt;br /&gt;
# Functors in general do not preserve mono- nor epimorphisms. We build a counter-example for monomorphisms. Let &amp;lt;math&amp;gt;\mathbf{2}&amp;lt;/math&amp;gt; be the category with two objects &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt;, and exactly one morphism &amp;lt;math&amp;gt;m \colon \star \to \bullet&amp;lt;/math&amp;gt;. This is a preorder, so &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; is monic. Now take &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; with two objects &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt;, exactly one morphism &amp;lt;math&amp;gt;m \colon \star \to \bullet&amp;lt;/math&amp;gt;, and one extra morphism &amp;lt;math&amp;gt;n \colon \star \to \star&amp;lt;/math&amp;gt;, different from the identity. Because of &amp;lt;math&amp;gt;n \neq id_\star&amp;lt;/math&amp;gt;, yet &amp;lt;math&amp;gt;m \circ n = m \circ id&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; is not monic in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;. The functor which sends &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathbf{2}&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, does not preserve monomorphisms.&lt;br /&gt;
# In general, the answer is (again) no. For monos, take for example the functor &amp;lt;math&amp;gt;\mathcal{C} \to \mathbf{2}&amp;lt;/math&amp;gt; which sends &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; to the identity. Yet, when &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is &#039;&#039;faithful&#039;&#039;, then &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; is monic (or epic).&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is faithful when, for any two morphisms &amp;lt;math&amp;gt;f, g&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Ff = Fg&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;f=g&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is injective on morphisms).&lt;br /&gt;
}}&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is full when, for any two objects &amp;lt;math&amp;gt;A, B&amp;lt;/math&amp;gt;, if &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; is a morphism &amp;lt;math&amp;gt;FA \to FB&amp;lt;/math&amp;gt;, then there exists &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;Ff = g&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is surjective on morphisms).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Find an &amp;quot;interesting&amp;quot; functor from &#039;&#039;&#039;Set&#039;&#039;&#039; to &#039;&#039;&#039;Group&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
Let &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; be the functor which sends:&lt;br /&gt;
* every set &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; to the free group generated by &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* every function &amp;lt;math&amp;gt;f \colon X \to Y&amp;lt;/math&amp;gt; to a group morphism defined by: &amp;lt;math&amp;gt;Ff(x_1^{\alpha_1}\times\dots\times x_k^{\alpha_k})=f(x_1)^{\alpha_1} \times \dots \times f(x_k)^{\alpha_k}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; is a locally small category and &#039;&#039;A&#039;&#039; one of its objects, let &amp;lt;math&amp;gt;Y_A : X \mapsto \mathcal{C}[X,A]&amp;lt;/math&amp;gt;. Show that this operation from objects of &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to sets can be extended into a contravariant functor &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to &#039;&#039;&#039;Set&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
Let &amp;lt;math&amp;gt;f\colon X \to Y&amp;lt;/math&amp;gt; be a morphism in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;Y_A(f)&amp;lt;/math&amp;gt; is expected to be a function from the set &amp;lt;math&amp;gt;\mathcal{C}[Y, A]&amp;lt;/math&amp;gt; to the set &amp;lt;math&amp;gt;\mathcal{C}[X, A]&amp;lt;/math&amp;gt;. We can take, for any morphism &amp;lt;math&amp;gt;m \in \mathcal{C}[Y,A]&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;Y_A(f)(m) = m \circ f&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This extends &amp;lt;math&amp;gt;Y_A&amp;lt;/math&amp;gt; to a contravariant functor, since &amp;lt;math&amp;gt;Y_A(id_X) = id_{\mathcal{C}[X, A]}&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;Y_A(f \circ g)(m) = m \circ (f \circ g) = (m \circ f) \circ g = (Y_A(g) \circ Y_A(f))(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Natural Transformations===&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
Let &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; be two functors &amp;lt;math&amp;gt;\mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;. A natural transformation &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; from &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; is given by:&lt;br /&gt;
* a morphism &amp;lt;math&amp;gt;\alpha_A \colon FA \to GA&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt; for every object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;,&lt;br /&gt;
* such that, for any morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;Gf \circ \alpha_A = \alpha_B \circ Ff&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;P(X)&amp;lt;/math&amp;gt; is the set of permutation of a (finite) set &#039;&#039;X&#039;&#039;; and &amp;lt;math&amp;gt;L(X)&amp;lt;/math&amp;gt; the set of its linear orderings, we have &amp;lt;math&amp;gt;\#(L(X)) = \#(L(X)) = n!&amp;lt;/math&amp;gt; where &amp;lt;math&amp;gt;n = \#(X)&amp;lt;/math&amp;gt;. Thus, there is a bijection (iso in &#039;&#039;&#039;Set&#039;&#039;&#039;) between &#039;&#039;P(X)&#039;&#039; and &#039;&#039;L(X)&#039;&#039;.&lt;br /&gt;
# Show that we can extend &#039;&#039;P&#039;&#039; and &#039;&#039;L&#039;&#039; to functors from &#039;&#039;&#039;B&#039;&#039;&#039; to &#039;&#039;&#039;Set&#039;&#039;&#039;, where &#039;&#039;&#039;B&#039;&#039;&#039; is the category of finite sets and bijections,&lt;br /&gt;
# Show that there can be no natural transformation from &#039;&#039;P&#039;&#039; to &#039;&#039;L&#039;&#039;,&lt;br /&gt;
# Conclude that there is no natural isomorphism between &#039;&#039;P&#039;&#039; and &#039;&#039;L&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Limits and colimits==&lt;br /&gt;
&lt;br /&gt;
One of the main thrusts of category theory is to define concepts by&lt;br /&gt;
their properties rather than by explicit construction. In general this&lt;br /&gt;
is just called abstraction, but in good cases, concepts are&lt;br /&gt;
&#039;&#039;defined&#039;&#039; by their properties, at least canonically if not uniquely.&lt;br /&gt;
&lt;br /&gt;
The chief example of this is binary products in &#039;&#039;&#039;Set&#039;&#039;&#039;.  The&lt;br /&gt;
product &amp;lt;math&amp;gt;A \times B&amp;lt;/math&amp;gt; of two sets &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is generally thought of as the set of pairs &amp;lt;math&amp;gt; (x,&lt;br /&gt;
y) &amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;x \in A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;y \in B&amp;lt;/math&amp;gt;.  But&lt;br /&gt;
strictly speaking, or rather set-theoretically speaking, one has to&lt;br /&gt;
construct it by cautious use of the axioms of Zermelo-Fraenkel set&lt;br /&gt;
theory.&lt;br /&gt;
&lt;br /&gt;
Instead, in any category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, for any objects&lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; categorists put: &lt;br /&gt;
&lt;br /&gt;
{{Definition | A&lt;br /&gt;
&#039;&#039;product&#039;&#039; of &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is an object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt;&lt;br /&gt;
with arrows&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{\pi_1} C \xrightarrow{\pi_2} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
such that for any object &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; and arrows&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{f} D \xrightarrow{g} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
there exists a unique arrow &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; making the diagram&lt;br /&gt;
[[Image:prod.png|center|Universal property of product]]&lt;br /&gt;
commute, i.e., &amp;lt;math&amp;gt;\pi_1 \circ h = f&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\pi_2 \circ h = g&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
The standard constructions in &#039;&#039;&#039;Set&#039;&#039;&#039; all have this property, and&lt;br /&gt;
all the non-standard ones you can think of also do, e.g., the set of&lt;br /&gt;
pairs &amp;lt;math&amp;gt; (\emptyset, x, y) &amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;x \in A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;y&lt;br /&gt;
\in B&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Conversely, any set with this property is as good as any other&lt;br /&gt;
construction of &amp;lt;math&amp;gt;A \times B&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Products are determined &#039;&#039;canonically&#039;&#039; by this property&lt;br /&gt;
property. We will give a more precise meaning to this in later&lt;br /&gt;
lectures; for now we just state:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lemma.&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For any other product &amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{p} E \xrightarrow{q} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; of &lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, there is a unique isomorphism pair &amp;lt;math&amp;gt; (r, s) &amp;lt;/math&amp;gt; &lt;br /&gt;
such that the diagrams&lt;br /&gt;
&lt;br /&gt;
[[Image:prod-iso.png|upright=2]] and &lt;br /&gt;
[[Image:prod-iso-2.png|upright=2]]&lt;br /&gt;
&lt;br /&gt;
commute. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Adjunctions==&lt;br /&gt;
&lt;br /&gt;
===First examples and definition===&lt;br /&gt;
&lt;br /&gt;
====So-called &#039;&#039;free&#039;&#039; constructions in algebra: monoid, group, etc====&lt;br /&gt;
====Their universal property, the underlying functor====&lt;br /&gt;
====The isomorphism between hom-sets====&lt;br /&gt;
====Its naturality====&lt;br /&gt;
====Definition====&lt;br /&gt;
====On to the definition with &amp;lt;math&amp;gt;\eta&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt;====&lt;br /&gt;
&lt;br /&gt;
===The simplicity behind definitions:2-categories and adjunctions therein===&lt;br /&gt;
&lt;br /&gt;
====Definition of 2-categories====&lt;br /&gt;
====String diagrams====&lt;br /&gt;
====&#039;&#039;&#039;CAT&#039;&#039;&#039; as a 2-category====&lt;br /&gt;
====Adjunctions in a 2-category====&lt;br /&gt;
&lt;br /&gt;
===Other basic examples===&lt;br /&gt;
&lt;br /&gt;
====Discussion: any syntax defines the free something==== The issue of &lt;br /&gt;
variable binding.&lt;br /&gt;
====Adjunction between partial orders = Galois connection====&lt;br /&gt;
====&amp;lt;math&amp;gt;\times&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\Rightarrow&amp;lt;/math&amp;gt; in logic====&lt;br /&gt;
====Sets/graphs and categories====&lt;br /&gt;
&lt;br /&gt;
===Monads and resolutions===&lt;br /&gt;
&lt;br /&gt;
====Definition of a monad====&lt;br /&gt;
====String diagrams====&lt;br /&gt;
====Every adjunction yields a monad====&lt;br /&gt;
====Example of monoids again: resolutions====&lt;br /&gt;
&lt;br /&gt;
===Monadic adjunctions===&lt;br /&gt;
&lt;br /&gt;
====The category of resolutions====&lt;br /&gt;
====Eilenberg-Moore is terminal====&lt;br /&gt;
====Kleisli is initial====&lt;br /&gt;
====Monadic adjunctions====&lt;br /&gt;
====Algebraic theories====&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
&lt;br /&gt;
====Composing adjunctions====&lt;br /&gt;
====Preservation of limits/colimits====&lt;br /&gt;
====Freyd&#039;s existence theorem====&lt;br /&gt;
====Beck&#039;s monadicity theorem====&lt;br /&gt;
&lt;br /&gt;
==Course Complements, references==&lt;br /&gt;
&lt;br /&gt;
One of the best books about category theory is&lt;br /&gt;
* Saunder MacLane, &#039;&#039;&amp;quot;Categories for the Working Mathematician&amp;quot;&#039;&#039;.&lt;br /&gt;
It is a little &amp;quot;dry&amp;quot;, in the sense that learning categories from it is not the easiest task on earth, but it still is one of the best references.&lt;br /&gt;
&lt;br /&gt;
I haven&#039;t really read it carefully, but here is [http://en.wikipedia.org/wiki/Category_theory what Wikipedia has to say on category theory].&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Langage_et_concepts_cat%C3%A9goriques_pour_les_math%C3%A9matiques_et_l%E2%80%99informatique&amp;diff=3943</id>
		<title>Langage et concepts catégoriques pour les mathématiques et l’informatique</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Langage_et_concepts_cat%C3%A9goriques_pour_les_math%C3%A9matiques_et_l%E2%80%99informatique&amp;diff=3943"/>
		<updated>2009-03-10T14:51:54Z</updated>

		<summary type="html">&lt;p&gt;Hatat : /* Functors */ Exos corrigés&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a wiki for a course at the MSTII &amp;quot;École doctorale&amp;quot; of Grenoble.&lt;br /&gt;
&lt;br /&gt;
Students are encouraged to participate by extending the wiki, adding proofs, corrections for exercices etc. To be able to modify the wiki, you need to register (upper right corner). Please use your real name...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===News===&lt;br /&gt;
&lt;br /&gt;
Courses are on wednesdays morning, 9&#039;00 to 12&#039;00 in room F218 at the &amp;quot;UFR IMAG&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* first course on the 25th of February: categories, functors, natural transformations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Basic Concepts==&lt;br /&gt;
&lt;br /&gt;
===Categories===&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A concrete category is given by:&lt;br /&gt;
* a collection of sets &#039;&#039;with structure&#039;&#039;,&lt;br /&gt;
* for any pair of such sets, a set of &#039;&#039;morphisms&#039;&#039; preserving the structure.&lt;br /&gt;
Morphisms should compose, and the identity should be a morphism.}}&lt;br /&gt;
&lt;br /&gt;
This definition is a little informal, but here are some examples:&lt;br /&gt;
* &#039;&#039;&#039;Grp&#039;&#039;&#039;: groups and group morphisms&lt;br /&gt;
* &#039;&#039;&#039;Top&#039;&#039;&#039;: topological spaces and continuous functions&lt;br /&gt;
* &#039;&#039;&#039;Ring&#039;&#039;&#039;: rings and rings morphisms&lt;br /&gt;
* &#039;&#039;&#039;Vect&#039;&#039;&#039;: vectors spaces and linear maps&lt;br /&gt;
* &#039;&#039;&#039;CPO&#039;&#039;&#039;: CPOs and continuous functions&lt;br /&gt;
* ...&lt;br /&gt;
* &#039;&#039;&#039;Set&#039;&#039;&#039;: sets and functions (&#039;&#039;&#039;ie&#039;&#039;&#039; sets with no structures, and arbitrary functions)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Generalizing the definition, we obtain the official definition of category:&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; is given by:&lt;br /&gt;
* a collection &amp;lt;math&amp;gt;\mathcal{C}_o&amp;lt;/math&amp;gt; of &#039;&#039;objects&#039;&#039;,  (notation: &amp;lt;math&amp;gt;A,B,C,X,Y,...&amp;lt;/math&amp;gt;)&lt;br /&gt;
* for each pair &amp;lt;math&amp;gt;A,B&amp;lt;/math&amp;gt; of objects, a collection &amp;lt;math&amp;gt;\mathcal{C}[A,B]&amp;lt;/math&amp;gt; of &#039;&#039;morphisms from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;&#039;,  (notation &amp;lt;math&amp;gt; f : A\to B&amp;lt;/math&amp;gt;)&lt;br /&gt;
* for any object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, a special morphism &amp;lt;math&amp;gt;i_A : A\to A&amp;lt;/math&amp;gt;&lt;br /&gt;
* for all objects &amp;lt;math&amp;gt;A,B,C&amp;lt;/math&amp;gt;, a composition &amp;lt;math&amp;gt;\circ : \mathcal{C}[B,C] \times \mathcal{C}[A,B] \to \mathcal{C}[A,C]&amp;lt;/math&amp;gt;,&lt;br /&gt;
such that:&lt;br /&gt;
* &amp;lt;math&amp;gt;f \in \mathcal{C}[A,B] \implies f\circ i_A = i_B\circ f = f&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;f\circ(g\circ h) = (f\circ g)\circ h&amp;lt;/math&amp;gt; whenever it makes sense.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
All concrete categories are categories, and here are some examples that are not obviously concrete:&lt;br /&gt;
* &#039;&#039;&#039;Graph&#039;&#039;&#039;: graphs and graph morphisms&lt;br /&gt;
* &#039;&#039;&#039;Rel&#039;&#039;&#039;: sets and relations&lt;br /&gt;
* &#039;&#039;&#039;Set×Set&#039;&#039;&#039;: pairs of sets, pairs of functions&lt;br /&gt;
* &#039;&#039;&#039;Set&amp;lt;math&amp;gt;^{op}&amp;lt;/math&amp;gt;&#039;&#039;&#039;: opposite of &#039;&#039;&#039;Set&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;, whenever (&#039;&#039;&#039;P&#039;&#039;&#039;,&amp;lt;) is a preorder (at most one morphism between objects)&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039;, whenever (&#039;&#039;&#039;M&#039;&#039;&#039;,e,×) is a monoid (a single object)&lt;br /&gt;
&lt;br /&gt;
We sometimes write &amp;lt;math&amp;gt;gf&amp;lt;/math&amp;gt; instead of &amp;lt;math&amp;gt;g \circ f&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a given category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, there are analogues of the notions of injective and surjective functions in &#039;&#039;&#039;Set&#039;&#039;&#039;. We will see that on concrete categories, they are actually slightly more general. The idea of injectivity gives rise to &#039;&#039;monomorphisms&#039;&#039;, and surjectivity gives rise to &#039;&#039;epimorphisms&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
&lt;br /&gt;
A morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; is a &#039;&#039;monomorphism&#039;&#039; iff for all object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; and morphisms &amp;lt;math&amp;gt;g,h \colon C \to A&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;fg = fh&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;g = h&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The morphism &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; is an &#039;&#039;epimorphism&#039;&#039; when it is a monomorphism in &amp;lt;math&amp;gt;\mathcal{C}^{op}&amp;lt;/math&amp;gt;. Explicitly, when for all object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; and morphisms &amp;lt;math&amp;gt;g,h \colon B \to C&amp;lt;/math&amp;gt;, we have &amp;lt;math&amp;gt;gf = hf&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;g = h&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
  isomorphism&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
# Prove that in &#039;&#039;&#039;Set&#039;&#039;&#039;, epic is equivalent to surjective and monic is equivalent to injective.&lt;br /&gt;
# Prove the same thing in &#039;&#039;&#039;Ab&#039;&#039;&#039;, the category of commutative groups. (One thing is not obvious.)&lt;br /&gt;
# Prove the same thing in &#039;&#039;&#039;Grp&#039;&#039;&#039;, the category of (non necessarily commutative) groups. (One thing is not obvious at all.)&lt;br /&gt;
# Prove that &amp;lt;math&amp;gt;i : \mathbf{Z} \to \mathbf{Q}&amp;lt;/math&amp;gt; is an epimorphism in the category of rings with multiplicative neutral. (Note that it is not surjective.)&lt;br /&gt;
# In &#039;&#039;&#039;Set&#039;&#039;&#039;, we saw that &#039;&#039;f&#039;&#039; is a monic iff &amp;lt;math&amp;gt;\forall x,y : 1 \to A, f\circ x = f\circ y \implies x=y&amp;lt;/math&amp;gt;, where 1 is any singleton set. Can you find a set &#039;&#039;C&#039;&#039; such that &#039;&#039;f&#039;&#039; is epic iff &amp;lt;math&amp;gt;\forall p,q : B \to C, p\circ f = j\circ f \implies p=q&amp;lt;/math&amp;gt;?&lt;br /&gt;
# In &#039;&#039;&#039;Group&#039;&#039;&#039;, can you find an object playing a role similar to 1, &#039;&#039;ie&#039;&#039; a group &#039;&#039;G&#039;&#039; s.t. &#039;&#039;f&#039;&#039; is monic iff &amp;lt;math&amp;gt;\forall x,y : G \to A, f\circ x = f\circ y \implies x=y&amp;lt;/math&amp;gt;. (We saw that we cannot use the singleton group ({e},e,×) to do that...)&lt;br /&gt;
&lt;br /&gt;
===Functors===&lt;br /&gt;
&lt;br /&gt;
Informally, a functor is a map between two categories which somehow preserves the structure of categories (namely, composition).&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; from a category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to a category &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt;, noted &amp;lt;math&amp;gt;F \colon \mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;, is given by:&lt;br /&gt;
* a map which sends every object &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to an object &amp;lt;math&amp;gt;FA&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* a map which sends every morphism &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, to a morphism &amp;lt;math&amp;gt;Ff&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{D}[FA, FB]&amp;lt;/math&amp;gt;,&lt;br /&gt;
such that:&lt;br /&gt;
* &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; preserves identities, i.e., &amp;lt;math&amp;gt;F(id_A) = id_{FA}&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; preserves composition: &amp;lt;math&amp;gt;F(f \circ g) = F(f) \circ F(g)&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
# Take a functor &amp;lt;math&amp;gt;F \colon \mathcal{C} \to \mathcal{D}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;f, g, h&amp;lt;/math&amp;gt; three morphisms in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, and &amp;lt;math&amp;gt;f&#039; = Ff&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g&#039; = Fg&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;h&#039; = Fh&amp;lt;/math&amp;gt;. When &amp;lt;math&amp;gt;h&#039; = f&#039; \circ g&#039;&amp;lt;/math&amp;gt;, can we say something interesting about &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;?&lt;br /&gt;
# Do functors preserve monomorphisms? Do functors preserve epimorphisms?&lt;br /&gt;
# Let &#039;&#039;F&#039;&#039; be a functor and &#039;&#039;F(f) = g&#039;&#039;, if &#039;&#039;g&#039;&#039; is a mono (resp. epi), is &#039;&#039;f&#039;&#039; a mono (resp. epi)?&lt;br /&gt;
If not, try to find some simple and natural condition on the functor to make that true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
# No, since &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; may not even compose! This is the case when &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;A \to B&amp;lt;/math&amp;gt;, and &amp;lt;math&amp;gt;g \colon C \to D&amp;lt;/math&amp;gt;, with &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; collapsing &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; (i.e., &amp;lt;math&amp;gt;FA = FD&amp;lt;/math&amp;gt;).&lt;br /&gt;
# Functors in general do not preserve mono- nor epimorphisms. We build a counter-example for monomorphisms. Let &amp;lt;math&amp;gt;\mathbf{2}&amp;lt;/math&amp;gt; be the category with two objects &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt;, and exactly one morphism &amp;lt;math&amp;gt;m \colon \star \to \bullet&amp;lt;/math&amp;gt;. This is a preorder, so &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; is monic. Now take &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; with two objects &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt;, exactly one morphism &amp;lt;math&amp;gt;m \colon \star \to \bullet&amp;lt;/math&amp;gt;, and one extra morphism &amp;lt;math&amp;gt;n \colon \star \to \star&amp;lt;/math&amp;gt;, different from the identity. Because of &amp;lt;math&amp;gt;n \neq id_\star&amp;lt;/math&amp;gt;, yet &amp;lt;math&amp;gt;m \circ n = m \circ id&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; is not monic in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;. The functor which sends &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;\star&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathbf{2}&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, does not preserve monomorphisms.&lt;br /&gt;
# In general, the answer is (again) no. For monos, take for example the functor &amp;lt;math&amp;gt;\mathcal{C} \to \mathbf{2}&amp;lt;/math&amp;gt; which sends &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; to the identity. Yet, when &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is &#039;&#039;faithful&#039;&#039;, then &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; is monic (or epic).&lt;br /&gt;
&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is faithful when, for any two morphisms &amp;lt;math&amp;gt;f, g&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Ff = Fg&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;f=g&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is injective on morphisms).&lt;br /&gt;
}}&lt;br /&gt;
{{Definition |&lt;br /&gt;
A functor &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is full when, for any two objects &amp;lt;math&amp;gt;A, B&amp;lt;/math&amp;gt;, if &amp;lt;math&amp;gt;g&amp;lt;/math&amp;gt; is a morphism &amp;lt;math&amp;gt;FA \to FB&amp;lt;/math&amp;gt;, then there exists &amp;lt;math&amp;gt;f \colon A \to B&amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;Ff = g&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; is surjective on morphisms).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Find an &amp;quot;interesting&amp;quot; functor from &#039;&#039;&#039;Set&#039;&#039;&#039; to &#039;&#039;&#039;Group&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
Let &amp;lt;math&amp;gt;F&amp;lt;/math&amp;gt; be the functor which sends:&lt;br /&gt;
* every set &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; to the free group generated by &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, and&lt;br /&gt;
* every function &amp;lt;math&amp;gt;f \colon X \to Y&amp;lt;/math&amp;gt; to a group morphism defined by: &amp;lt;math&amp;gt;Ff(x_1^{\alpha_1}\times\dots\times x_k^{\alpha_k})=f(x_1)^{\alpha_1} \times \dots \times f(x_k)^{\alpha_k}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; is a locally small category and &#039;&#039;A&#039;&#039; one of its objects, let &amp;lt;math&amp;gt;Y_A : X \mapsto \mathcal{C}[X,A]&amp;lt;/math&amp;gt;. Show that this operation from objects of &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to sets can be extended into a contravariant functor &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt; to &#039;&#039;&#039;Set&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Answer&amp;lt;/u&amp;gt;&lt;br /&gt;
Let &amp;lt;math&amp;gt;f\colon X \to Y&amp;lt;/math&amp;gt; be a morphism in &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;Y_A(f)&amp;lt;/math&amp;gt; is expected to be a function from the set &amp;lt;math&amp;gt;\mathcal{C}[Y, A]&amp;lt;/math&amp;gt; to the set &amp;lt;math&amp;gt;\mathcal{C}[X, A]&amp;lt;/math&amp;gt;. We can take, for any morphism &amp;lt;math&amp;gt;m \in \mathcal{C}[Y,A]&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;Y_A(f)(m) = m \circ f&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This extends &amp;lt;math&amp;gt;Y_A&amp;lt;/math&amp;gt; to a contravariant functor, since &amp;lt;math&amp;gt;Y_A(id_X) = id_{\mathcal{C}[X, A]}&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;Y_A(f \circ g)(m) = m \circ (f \circ g) = (m \circ f) \circ g = (Y_A(g) \circ Y_A(f))(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Natural Transformations===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ...blabla...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Exercice&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;P(X)&amp;lt;/math&amp;gt; is the set of permutation of a (finite) set &#039;&#039;X&#039;&#039;; and &amp;lt;math&amp;gt;L(X)&amp;lt;/math&amp;gt; the set of its linear orderings, we have &amp;lt;math&amp;gt;\#(L(X)) = \#(L(X)) = n!&amp;lt;/math&amp;gt; where &amp;lt;math&amp;gt;n = \#(X)&amp;lt;/math&amp;gt;. Thus, there is a bijection (iso in &#039;&#039;&#039;Set&#039;&#039;&#039;) between &#039;&#039;P(X)&#039;&#039; and &#039;&#039;L(X)&#039;&#039;.&lt;br /&gt;
# Show that we can extend &#039;&#039;P&#039;&#039; and &#039;&#039;L&#039;&#039; to functors from &#039;&#039;&#039;B&#039;&#039;&#039; to &#039;&#039;&#039;Set&#039;&#039;&#039;, where &#039;&#039;&#039;B&#039;&#039;&#039; is the category of finite sets and bijections,&lt;br /&gt;
# Show that there can be no natural transformation from &#039;&#039;P&#039;&#039; to &#039;&#039;L&#039;&#039;,&lt;br /&gt;
# Conclude that there is no natural isomorphism between &#039;&#039;P&#039;&#039; and &#039;&#039;L&#039;&#039;.&lt;br /&gt;
==Limits and colimits==&lt;br /&gt;
&lt;br /&gt;
One of the main thrusts of category theory is to define concepts by&lt;br /&gt;
their properties rather than by explicit construction. In general this&lt;br /&gt;
is just called abstraction, but in good cases, concepts are&lt;br /&gt;
&#039;&#039;defined&#039;&#039; by their properties, at least canonically if not uniquely.&lt;br /&gt;
&lt;br /&gt;
The chief example of this is binary products in &#039;&#039;&#039;Set&#039;&#039;&#039;.  The&lt;br /&gt;
product &amp;lt;math&amp;gt;A \times B&amp;lt;/math&amp;gt; of two sets &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is generally thought of as the set of pairs &amp;lt;math&amp;gt; (x,&lt;br /&gt;
y) &amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;x \in A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;y \in B&amp;lt;/math&amp;gt;.  But&lt;br /&gt;
strictly speaking, or rather set-theoretically speaking, one has to&lt;br /&gt;
construct it by cautious use of the axioms of Zermelo-Fraenkel set&lt;br /&gt;
theory.&lt;br /&gt;
&lt;br /&gt;
Instead, in any category &amp;lt;math&amp;gt;\mathcal{C}&amp;lt;/math&amp;gt;, for any objects&lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; categorists put: &lt;br /&gt;
&lt;br /&gt;
{{Definition | A&lt;br /&gt;
&#039;&#039;product&#039;&#039; of &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is an object &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt;&lt;br /&gt;
with arrows&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{\pi_1} C \xrightarrow{\pi_2} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
such that for any object &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; and arrows&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{f} D \xrightarrow{g} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
there exists a unique arrow &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; making the diagram&lt;br /&gt;
[[Image:prod.png|center|Universal property of product]]&lt;br /&gt;
commute, i.e., &amp;lt;math&amp;gt;\pi_1 \circ h = f&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\pi_2 \circ h = g&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
The standard constructions in &#039;&#039;&#039;Set&#039;&#039;&#039; all have this property, and&lt;br /&gt;
all the non-standard ones you can think of also do, e.g., the set of&lt;br /&gt;
pairs &amp;lt;math&amp;gt; (\emptyset, x, y) &amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;x \in A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;y&lt;br /&gt;
\in B&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Conversely, any set with this property is as good as any other&lt;br /&gt;
construction of &amp;lt;math&amp;gt;A \times B&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Products are determined &#039;&#039;canonically&#039;&#039; by this property&lt;br /&gt;
property. We will give a more precise meaning to this in later&lt;br /&gt;
lectures; for now we just state:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lemma.&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For any other product &amp;lt;center&amp;gt;&amp;lt;math&amp;gt;A \xleftarrow{p} E \xrightarrow{q} B&amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; of &lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, there is a unique isomorphism pair &amp;lt;math&amp;gt; (r, s) &amp;lt;/math&amp;gt; &lt;br /&gt;
such that the diagrams&lt;br /&gt;
&lt;br /&gt;
[[Image:prod-iso.png|upright=2]] and &lt;br /&gt;
[[Image:prod-iso-2.png|upright=2]]&lt;br /&gt;
&lt;br /&gt;
commute. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Adjunctions==&lt;br /&gt;
&lt;br /&gt;
===First examples and definition===&lt;br /&gt;
&lt;br /&gt;
====So-called &#039;&#039;free&#039;&#039; constructions in algebra: monoid, group, etc====&lt;br /&gt;
====Their universal property, the underlying functor====&lt;br /&gt;
====The isomorphism between hom-sets====&lt;br /&gt;
====Its naturality====&lt;br /&gt;
====Definition====&lt;br /&gt;
====On to the definition with &amp;lt;math&amp;gt;\eta&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\epsilon&amp;lt;/math&amp;gt;====&lt;br /&gt;
&lt;br /&gt;
===The simplicity behind definitions:2-categories and adjunctions therein===&lt;br /&gt;
&lt;br /&gt;
====Definition of 2-categories====&lt;br /&gt;
====String diagrams====&lt;br /&gt;
====&#039;&#039;&#039;CAT&#039;&#039;&#039; as a 2-category====&lt;br /&gt;
====Adjunctions in a 2-category====&lt;br /&gt;
&lt;br /&gt;
===Other basic examples===&lt;br /&gt;
&lt;br /&gt;
====Discussion: any syntax defines the free something==== The issue of &lt;br /&gt;
variable binding.&lt;br /&gt;
====Adjunction between partial orders = Galois connection====&lt;br /&gt;
====&amp;lt;math&amp;gt;\times&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;\Rightarrow&amp;lt;/math&amp;gt; in logic====&lt;br /&gt;
====Sets/graphs and categories====&lt;br /&gt;
&lt;br /&gt;
===Monads and resolutions===&lt;br /&gt;
&lt;br /&gt;
====Definition of a monad====&lt;br /&gt;
====String diagrams====&lt;br /&gt;
====Every adjunction yields a monad====&lt;br /&gt;
====Example of monoids again: resolutions====&lt;br /&gt;
&lt;br /&gt;
===Monadic adjunctions===&lt;br /&gt;
&lt;br /&gt;
====The category of resolutions====&lt;br /&gt;
====Eilenberg-Moore is terminal====&lt;br /&gt;
====Kleisli is initial====&lt;br /&gt;
====Monadic adjunctions====&lt;br /&gt;
====Algebraic theories====&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
&lt;br /&gt;
====Composing adjunctions====&lt;br /&gt;
====Preservation of limits/colimits====&lt;br /&gt;
====Freyd&#039;s existence theorem====&lt;br /&gt;
====Beck&#039;s monadicity theorem====&lt;br /&gt;
&lt;br /&gt;
==Course Complements, references==&lt;br /&gt;
&lt;br /&gt;
One of the best books about category theory is&lt;br /&gt;
* Saunder MacLane, &#039;&#039;&amp;quot;Categories for the Working Mathematician&amp;quot;&#039;&#039;.&lt;br /&gt;
It is a little &amp;quot;dry&amp;quot;, in the sense that learning categories from it is not the easiest task on earth, but it still is one of the best references.&lt;br /&gt;
&lt;br /&gt;
I haven&#039;t really read it carefully, but here is [http://en.wikipedia.org/wiki/Category_theory what Wikipedia has to say on category theory].&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante_d%C3%A9but&amp;diff=3940</id>
		<title>Modèle:Boîte déroulante début</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante_d%C3%A9but&amp;diff=3940"/>
		<updated>2009-03-10T13:37:50Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3939</id>
		<title>Modèle:Boîte déroulante</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3939"/>
		<updated>2009-03-10T13:36:32Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3938</id>
		<title>Modèle:Boîte déroulante</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3938"/>
		<updated>2009-03-10T13:26:32Z</updated>

		<summary type="html">&lt;p&gt;Hatat : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#ifeq:{{{br|yes}}}|yes|&amp;lt;p style=&amp;quot;margin:0; padding:0; line-height:1em;&amp;quot;&amp;gt;&amp;lt;br clear=&amp;quot;all&amp;quot; style=&amp;quot;margin:0; padding:0; clear:both; line-height:1em;&amp;quot;/&amp;gt;&amp;lt;/p&amp;gt;|}}&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-right:.5em;&amp;quot; align=&amp;quot;{{#if:{{{alignB|}}}|{{{alignB}}}|left}}&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavFrame&amp;quot; style=&amp;quot;margin-top:{{{margeHaut|0em}}}; margin-bottom:{{{margeBas|0.5em}}}; width:{{{largeur|99%}}}; border-style:solid; -moz-border-radius:{{{arrondi|0}}};border-color:{{{couleurBordure|#AAAAAA}}}; background-color:{{{couleurFondB|#FFFFFF}}};&amp;quot; title=&amp;quot;{{{label|&amp;lt;nowiki&amp;gt;[Dérouler]&amp;lt;/nowiki&amp;gt;}}}&amp;quot;&amp;gt;&lt;br /&gt;
{{#if:{{{image|}}}|&amp;lt;div class=&amp;quot;NavPic&amp;quot; style=&amp;quot;background-color:{{{couleurFondT|#EFEFEF}}};&amp;quot;&amp;gt;{{{image}}}&amp;lt;/div&amp;gt;}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavHead&amp;quot; align=&amp;quot;{{{alignT|center}}}&amp;quot; style=&amp;quot;height:{{{hauteur|1.6em}}}; background-color:{{{couleurFondT|#EFEFEF}}}; color:{{{couleurTexteT|black}}}; {{#ifeq:{{{thinning|no}}}|yes|font-weight:normal;|}}&amp;quot;&amp;gt;{{{titre}}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavContent&amp;quot; style=&amp;quot;margin:{{{marge|0px}}}; background:{{{couleurFond|white}}}; display:block; font-size:{{{taille|1em}}}&amp;quot; align=&amp;quot;{{{align|left}}}&amp;quot;&amp;gt;&lt;br /&gt;
{{{contenu}}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavEnd&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante_d%C3%A9but&amp;diff=3937</id>
		<title>Modèle:Boîte déroulante début</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante_d%C3%A9but&amp;diff=3937"/>
		<updated>2009-03-10T13:24:49Z</updated>

		<summary type="html">&lt;p&gt;Hatat : a déplacé Modèle:Boîte déroulante début vers Modèle:Boîte déroulante&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Modèle:Boîte déroulante]]&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3936</id>
		<title>Modèle:Boîte déroulante</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3936"/>
		<updated>2009-03-10T13:24:49Z</updated>

		<summary type="html">&lt;p&gt;Hatat : a déplacé Modèle:Boîte déroulante début vers Modèle:Boîte déroulante&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#ifeq:{{{br|yes}}}|yes|&amp;lt;p style=&amp;quot;margin:0; padding:0; line-height:1em;&amp;quot;&amp;gt;&amp;lt;br clear=&amp;quot;all&amp;quot; style=&amp;quot;margin:0; padding:0; clear:both; line-height:1em;&amp;quot;/&amp;gt;&amp;lt;/p&amp;gt;|}}&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-right:.5em;&amp;quot; align=&amp;quot;{{#if:{{{alignB|}}}|{{{alignB}}}|left}}&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavFrame&amp;quot; style=&amp;quot;margin-top:{{{margeHaut|0em}}}; margin-bottom:{{{margeBas|0.5em}}}; width:{{{largeur|99%}}}; border-style:solid; -moz-border-radius:{{{arrondi|0}}};border-color:{{{couleurBordure|#AAAAAA}}}; background-color:{{{couleurFondB|#FFFFFF}}};&amp;quot; title=&amp;quot;{{{label|&amp;lt;nowiki&amp;gt;[Dérouler]&amp;lt;/nowiki&amp;gt;}}}&amp;quot;&amp;gt;&lt;br /&gt;
{{#if:{{{image|}}}|&amp;lt;div class=&amp;quot;NavPic&amp;quot; style=&amp;quot;background-color:{{{couleurFondT|#EFEFEF}}};&amp;quot;&amp;gt;{{{image}}}&amp;lt;/div&amp;gt;}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavHead&amp;quot; align=&amp;quot;{{{alignT|center}}}&amp;quot; style=&amp;quot;height:{{{hauteur|1.6em}}}; background-color:{{{couleurFondT|#EFEFEF}}}; color:{{{couleurTexteT|black}}}; {{#ifeq:{{{thinning|no}}}|yes|font-weight:normal;|}}&amp;quot;&amp;gt;{{{titre}}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavContent&amp;quot; style=&amp;quot;margin:{{{marge|0px}}}; background:{{{couleurFond|white}}}; display:block; font-size:{{{taille|1em}}}&amp;quot; align=&amp;quot;{{{align|left}}}&amp;quot;&amp;gt;&lt;br /&gt;
{{{contenu}}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavEnd&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Catégories et interwikis en sous-page de documentation, merci. --&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
	<entry>
		<id>http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3935</id>
		<title>Modèle:Boîte déroulante</title>
		<link rel="alternate" type="text/html" href="http://os-vps418.infomaniak.ch:1250/mediawiki/index.php?title=Mod%C3%A8le:Bo%C3%AEte_d%C3%A9roulante&amp;diff=3935"/>
		<updated>2009-03-10T13:24:13Z</updated>

		<summary type="html">&lt;p&gt;Hatat : Modèle d&amp;#039;une boîte dont le contenu est caché par défaut&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#ifeq:{{{br|yes}}}|yes|&amp;lt;p style=&amp;quot;margin:0; padding:0; line-height:1em;&amp;quot;&amp;gt;&amp;lt;br clear=&amp;quot;all&amp;quot; style=&amp;quot;margin:0; padding:0; clear:both; line-height:1em;&amp;quot;/&amp;gt;&amp;lt;/p&amp;gt;|}}&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-right:.5em;&amp;quot; align=&amp;quot;{{#if:{{{alignB|}}}|{{{alignB}}}|left}}&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavFrame&amp;quot; style=&amp;quot;margin-top:{{{margeHaut|0em}}}; margin-bottom:{{{margeBas|0.5em}}}; width:{{{largeur|99%}}}; border-style:solid; -moz-border-radius:{{{arrondi|0}}};border-color:{{{couleurBordure|#AAAAAA}}}; background-color:{{{couleurFondB|#FFFFFF}}};&amp;quot; title=&amp;quot;{{{label|&amp;lt;nowiki&amp;gt;[Dérouler]&amp;lt;/nowiki&amp;gt;}}}&amp;quot;&amp;gt;&lt;br /&gt;
{{#if:{{{image|}}}|&amp;lt;div class=&amp;quot;NavPic&amp;quot; style=&amp;quot;background-color:{{{couleurFondT|#EFEFEF}}};&amp;quot;&amp;gt;{{{image}}}&amp;lt;/div&amp;gt;}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavHead&amp;quot; align=&amp;quot;{{{alignT|center}}}&amp;quot; style=&amp;quot;height:{{{hauteur|1.6em}}}; background-color:{{{couleurFondT|#EFEFEF}}}; color:{{{couleurTexteT|black}}}; {{#ifeq:{{{thinning|no}}}|yes|font-weight:normal;|}}&amp;quot;&amp;gt;{{{titre}}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavContent&amp;quot; style=&amp;quot;margin:{{{marge|0px}}}; background:{{{couleurFond|white}}}; display:block; font-size:{{{taille|1em}}}&amp;quot; align=&amp;quot;{{{align|left}}}&amp;quot;&amp;gt;&lt;br /&gt;
{{{contenu}}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;NavEnd&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Catégories et interwikis en sous-page de documentation, merci. --&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hatat</name></author>
	</entry>
</feed>