Brevet FR3140969A1 — publié le 20240419

Procédé de gestion d’un appel système et produit programme d’ordinateur associé Ce procédé, réalisé par un noyau (20) muni d’un moteur (34) consiste : détermination si un appel système d’un fil d’exécution applicatif est bloquant ; dans l’affirmative, mise en sommeil du fil d’exécution ; création d’une tâche asynchrone pour réaliser l’appel système et mise à jour d’une liste de tâches ; exécution par le moteur de la tâche sur une pile du noyau avec des informations relatives à la tâche stockées dans une zone mémoire, jusqu’à atteindre un état d’exécution bloquant nécessitant un évènement attendu ; lors de la survenue de l’évènement attendu, reprise de l’exécution de la tâche; vérification si l’état d’exécution atteint est un état d’exécution final de la tâche ; et, dans l’affirmative, finalisation de l’exécution de la tâche et suppression de la tâche de la liste de tâches ; et retour de l’appel système au fil d’exécution. Figure pour l'abrégé : Figure 1 Procédé de gestion d’un appel système et produit programme d’ordinateur associé L’invention a pour domaine celui de la programmation système. Le système d’exploitation (« operating system » en anglais) d’un ordinateur est un programme d’abstraction de la couche matérielle, jouant le rôle d’interface entre la couche applicative et la couche matérielle. Une application est un programme exécuté « au-dessus » du système d’exploitation et qui accède par conséquent à la couche matérielle indirectement via le système d’exploitation. Le système d’exploitation comporte un noyau et éventuellement d’autres programmes associés. Le noyau (« kernel ») est une partie du système d’exploitation qui répond aux appels système, aux interruptions et aux exceptions. Une application en cours d’exécution est un processus (« process »). Un processus est subdivisé en une pluralité de fils d'exécution (« thread »). Un fil d'exécution comporte un bloc d’instructions élémentaires exécutable en une seule fois par le processeur de l’ordinateur. Un fil d’exécution peut être dans différents états d’exécution : un état « running » (ou « en cours d’exécution »), un état « ready » (ou « prêt à être exécuté ») ou un état « waiting » ( ou « en attente »). Un fil d'exécution est associé à un contexte d’exécution. C’est l’ensemble des informations décrivant l’état d’exécution du fil d’exécution et permettant au processeur de poursuivre, d’interrompre ou de reprendre l’exécution de ce fil d’exécution. Le contexte comporte notamment une pile d’exécution (« stack ») dans la mémoire de l’ordinateur, le contenu des registres du processeur (comme les valeurs d’un compteur de programme, un pointeur de pile,…). Les instructions sont exécutées par le processeur dans un mode prédéfini de fonctionnement du processeur, en fonction des privilèges octroyés à ces instructions, notamment d’accès à certains espaces de la mémoire. Par exemple, les instructions d’un fil d’exécution d’une application sont exécutés dans un mode non-privilégié, par exemple le mode « utilisateur », alors que les instructions du système d’exploitation (notamment le noyau) sont exécutées dans un mode privilégié, comme le mode « noyau ». Dans un système d’exploitation multi-tâches, plusieurs processus sont exécutés en « parallèle ». Plus exactement, un ordonnanceur (« scheduler ») du noyau place les fils d’exécution qui sont dans l’état « ready » dans une file d’attente (« queue »), qui est une liste ordonnée des fils d’exécution. L’ordonnanceur utilise des règles de priorité pour ordonner les fils d’exécution dans cette file d’attente. Le processeur exécute le fil d’exécution placé au bas de la file d’attente. Celui-ci bascule alors de l’état « ready » à l’état « running ». Le processeur exécute ce fil d’exécution soit jusqu’à atteindre la fin de l’exécution des instructions de ce fil d’exécution, soit lorsqu’un temps d’exécution maximal pour un file d’exécution est atteint. Lorsque le processeur passe de l’exécution d’un premier fil d’exécution d’un premier processus à l’exécution d’un second fil d’exécution d’un second processus, il effectue un changement de contexte. Il y a changement de contexte même si les deux fils d’exécution appartiennent à un même processus. Tout au plus certaines informations communes aux deux fils d’exécution, comme l’espace d’adressage, les données de protections mémoire, etc. peuvent ne pas être modifiées. Mais les informations spécifiques à chaque fil d’exécution, comme le compteur de programme, le pointeur de pile, etc. doivent être modifiées. Lors d’un changement de contexte, le noyau est responsable de sauvegarder le contexte du premier fil d’exécution et de restaurer le contexte du second fil d’exécution. Pour la réalisation de certaines fonctions dites systèmes, un fil d’exécution fait appel aux services correspondant fournis par le noyau. On dit que le fil d’exécution fait un appel système. Pour cela les étapes suivantes sont successivement réalisées : - Le processeur exécute les instructions du fil d’exécution dans le mode non privilégié sur une pile d’exécution non-privilégiée du fil d’exécution. - Lorsqu’une de ces instructions correspond à un appel système, le processeur bascule dans du mode non-privilégié vers le mode privilégié, et exécute les instructions du noyau associées à la fonction système appelée sur une pile d’exécution privilégiée. - Une fois les instructions associées à la fonction système exécutées, le noyau retourne l’appel système en indiquant le résultat de l’appel système. - Le processeur bascule dans du mode privilégié vers le mode non-privilégié, et reprend l’exécution des instructions du fil d’exécution appelant sur la pile d’exécution non-privilégiée, en tenant compte du résultat de l’appel système. L’exécution du fil d’exécution appelant reprend par conséquent là où elle avait été suspendue suite à l’appel système. Il existe cependant deux types d’appels système, les appels système non-bloquants et les appels système bloquants. Dans un appel système non-bloquant, le noyau peut réaliser la tâche correspondant au service demandé, car il dispose des informations requises. Le noyau retourne alors immédiatement l’appel système. C’est ce qui a été présenté ci-dessus. Dans un appel système bloquant, le noyau ne peut pas réaliser la tâche correspondant au service demandé, car il n’a pas toutes les informations nécessaires. On est donc dans une situation où le fil d’exécution est bloqué tant que les informations requises ne sont pas disponibles. C’est par exemple le cas pour un appel système de lecture dans un tuyau de données (« pipe ») lorsque ce tuyau est vide. Le fil d’exécution est alors bloqué en lecture sur le tuyau. Le noyau retournera l’appel système uniquement lorsqu’une donnée sera disponible dans le tuyau surveillé, c’est-à-dire lors de la survenu d’un évènement du type « écriture » d’une donnée dans le tuyau surveillé. C’est par exemple encore le cas d’un appel système « sleep » consistant à attendre qu’un compteur de temps atteigne une certaine durée prédéfinie. Le fil d’exécution est alors bloqué tant que le compteur de temps n’a pas atteint la valeur requise. Le noyau retournera l’appel système uniquement lorsque le compteur de temps aura atteint la durée prédéfinie, c’est-à-dire lors de la survenu d’un évènement du type « égalité » entre la valeur courante du compteur de temps et la durée prédéfinie. La gestion d’un tel blocage du fil d’exécution, ainsi que la reprise de son exécution sont entièrement à la charge du noyau. Notamment, un fil d’exécution bloqué par un appel système bloquant est mis en attente par le noyau. Plus précisément, il est basculé de l’état « running » à l’état « waiting » et est retiré de la file d’attente des fils d’exécution à l’état « ready » de l’ordonnanceur pour qu’il ne puisse pas être exécuté. Son contexte d’exécution est sauvegardé (notamment la pile non-privilégiée sur laquelle il était exécuté) pour permettre au processeur de passer à l’exécution d’un autre fil d’exécution. Pour la reprise de l’exécution d’un fil d’exécution dans l’état « waiting », le noyau tient à jour une table indiquant tous les fils d’exécution dans l’état « waiting » et, pour chaque fil d’exécution, l’évènement nécessaires à sa reprise. Lors de la survenue de l’évènement attendu pour la reprise d’un fil d’exécution, le noyau reprend et termine l’exécution des instructions de l’appel système bloquant. Il met à jour le contexte du fil d’exécution avec le résultat de l’appel système. Il bascule enfin le fil d’exécution de l’état « waiting » à l’état « ready ». Le fil d’exécution est alors replacé dans la file d’attente par l’ordonnanceur en vue d’être à nouveau exécuté par le processeur. Actuellement, il existe deux modèles de noyau en fonction de la manière précise dont le noyau gère des appels systèmes bloquants : le noyau « process model » (ou noyau PM) d’une part et le noyau « IRQ Model » (ou noyau IRQ) d’autre part. Le noyau PM est fondé sur la présence de deux piles pour chaque fil d’exécution : une pile en mode non-privilégié (ou pile non-privilégiée) et une pile en mode privilégié (ou pile privilégiée). Si un fil d’exécution est bloqué, le contexte noyau du fil d’exécution est stocké dans la pile privilégiée du fil d’exécution, au moment où le fil d’exécution bascule de l’état « running » à l’état « waiting ». Lorsque l’évènement nécessaire à la reprise de ce fil d’exécution survient, le noyau utilise informations de la pile privilégiée du fil d’exécution pour finaliser l’appel système. La finalisation de cette tâche conduit automatiquement à une reprise de l’exécution du fil d’exécution appelant en le basculant de l’état « waiting » vers l’état « ready ». Cependant, dans ce premier modèle, le dimensionnement de la pile privilégiée d’un fil d’exécution est problématique. Il y a un risque élevé de débordement (« overflow ») sur d’autres cellules de la mémoire du noyau. Ceci soulève des questions majeures de sécurité et de fiabilité. Pour y parer, il y a une tendance à surdimensionner la pile privilégiée pour chaque fil d’exécution. Ceci conduit à une consommation importante des ressources de l’ordinateur. Mais, le code du noyau reste simple à développer et à comprendre par son développeur, car son aspect séquentiel est conservé. La sauvegarde du contexte noyau du fil d’exécution dans la pile privilégiée est transparente au développeur car gérée par le compilateur. Le noyau IRQ est fondé sur une pile non-privilégiée par fil d’exécution et une pile privilégiée commune à tous les fils d’exécution. La pile privilégiée commune est donc partagée entre les différents fils d’exécution. La pile privilégiée commune est cependant réinitialisée à l’issue de chaque appel système (bloquant ou non-bloquant), c’est-à-dire qu’aucune information n’est mémorisée sur la pile privilégiée commune. C’est donc au développeur du code du noyau de coder, pour les appels systèmes bloquants, la manière de stocker le contexte noyau du fil d’exécution dans des structures de données annexes, avec les conditions de déblocage, pour permettre la finalisation de l’appel système lors de la survenue de l’évènement attendu et la reprise du fil d’exécution appelant mis en sommeil. Ainsi, la partie du code source d’un noyau IRQ gérant la sauvegarde du contexte noyau est laissée aux soins du développeur. Si un tel noyau permet d’avoir une approche sécuritaire, la lecture du code source n’est plus séquentielle. Le code source est donc particulièrement difficile à lire et à vérifier. Le but de la présente invention est de proposer un modèle de noyau alternatif aux modèles de noyau de l’état de la technique, offrant une nouvelle approche pour la gestion des appels systèmes bloquants, tout en essayant de combiner les avantages des deux modèles connus et en évitant leurs inconvénients respectifs. Pour cela l’invention a pour objet un procédé de gestion d’un appel système, mis en œuvre par un noyau d’un système d’exploitation exécuté par un ordinateur, l’appel système ayant été émis par un fil d’exécution d’une application exécuté par l’ordinateur, caractérisé en ce que, ledit noyau comportant un ordonnanceur et un moteur d’exécution de tâches asynchrones, ledit procédé comporte les étapes de : a)- détermination par le noyau si l’appel système est un appel système bloquant ; et, dans l’affirmative : b)- mise en sommeil par le noyau du fil d’exécution ; c)- création par le noyau d’une tâche asynchrone pour réaliser l’appel système, la tâche asynchrone étant équivalente une machine à états, une transition d’un premier état d’exécution vers un second état d’exécution étant initiée par un évènement attendu, et mise à jour par le noyau d’une liste de tâches asynchrones à exécuter par le moteur avec les informations relatives à la tâche asynchrone créée ; d)- exécution par le moteur de la tâche asynchrone sur une pile du noyau en utilisant les informations de la zone mémoire relatives à la tâche asynchrone, jusqu’à atteindre un état d’exécution bloquant nécessitant un évènement attendu correspondant, l’exécution de la tâche asynchrone étant alors bloquée et la liste de tâches asynchrones mise à jour avec l’état d’exécution bloquant atteint et l’évènement attendu correspondant ; e)- lors de la survenue de l’évènement attendu correspondant, reprise de l’exécution par le moteur de la tâche asynchrone sur la pile du noyau de manière à effectuer la transition de l’état d’exécution bloquant vers un état d’exécution bloquant suivant ; f)- vérification si l’état d’exécution bloquant suivant est un état d’exécution final de la tâche ; et dans l’affirmative, g)- finalisation de l’exécution de la tâche asynchrone et suppression de la tâche asynchrone de la liste de tâches asynchrones à exécuter par le moteur ; et, h)- retour par le noyau de l’appel système au fil d’exécution et réveil par le noyau du fil d’exécution. Suivant des modes particuliers de réalisation, … comporte une ou plusieurs des caractéristiques suivantes, prises isolément ou suivant toutes les combinaisons techniquement possibles : - lorsque l’étape de vérification conduit à conclure que l’état d’exécution bloquant suivant n’est pas l’état d’exécution final de la tâche asynchrone, les étapes d), e) et f) sont itérées. - le procédé comporte, en outre, lorsque le noyau détermine que l’appel système reçu est un appel système non-bloquant, les étapes de : exécution par le noyau de l’appel système sur une pile du noyau ; et, retour par le noyau de l’appel système au fil d’exécution. - la mise en sommeil par le noyau du fil d’exécution consiste à basculer un état d’exécution du fil d’exécution d’un état « en cours d’exécution» à un état « en attente » et le réveil par le noyau du fil d’exécution consiste à basculer l’état d’exécution du fil d’exécution de l’état « en attente» à un état «prêt à être exécuté». - entre la mise en œuvre des étapes d) et e), un autre fil d’exécution présent dans une file d’attente de l’ordonnanceur est exécuté. - lors d’une interruption indicative de la survenue d’un nouvel évènement, le moteur est exécuté pour identifier la tâche asynchrone de la liste des tâches asynchrones pour laquelle le nouvel évènement constitue l’évènement attendu. L’invention a également pour objet un produit programme d’ordinateur comportant des instructions qui, lorsqu’elles sont exécutées par un processeur d’un ordinateur, munissent ledit ordinateur d’un noyau, caractérisé en ce que ledit noyau comporte un ordonnanceur et un moteur d’exécution de tâches asynchrones, ledit moteur de tâches asynchrones étant associé à une liste de tâches asynchrones à exécuter et une zone mémoire dédiée dans une mémoire de l’ordinateur, le noyau étant adapté, lors de la réception d’un appel système émis par un fil d’exécution d’une application exécutée par l’ordinateur, pour réaliser un procédé de gestion dudit appel système conforme au préocédé précédent. De préférence, le p roduit programme d’ordinateur est tel que le noyau est associé à une unique pile noyau. De préférence encore, le produit programme d’ordinateur résulte de la compilation d’un code source, ledit code source se présentant sous une forme séquentielle même pour les appels systèmes bloquants. L’invention et ses avantages seront mieux compris à la lecture de la description détaillée qui va suivre d’un mode de réalisation particulier, donné uniquement à titre d’exemple non limitatif, cette description étant faite en se référant aux dessins annexés sur lesquels : La est une représentation schématique sous forme de modules fonctionnels d’un mode de réalisation préféré d’un noyau selon l’invention ; La est une représentation schématique sous forme de blocs des étapes d’un appel système bloquant en exécutant le noyau de la ; et, La est une représentation schématique du principe de fonctionnement du noyau de la . La présente invention porte sur un produit programme d’ordinateur qui, lorsque ses instructions sont exécutées par un ordinateur, fournit une fonctionnalité de noyau à cet ordinateur. Dans ce qui suit on parlera plus simplement de noyau. En tant que programme d’ordinateur exécutable, le noyau est un code objet résultant de la compilation d’un code source, écrit dans un langage de programmation adapté. De manière générale, le noyau selon l’invention gère un blocage lié à un appel système bloquant au moyen d’une programmation asynchrone des appels systèmes bloquants. La représente un système d’exploitation 2 formant interface entre une couche matérielle 1 (processeur 11, mémoire 12, ports d’entrée/sortie 13, …) et une couche applicative 3, comportant un ou plusieurs programme(s) applicatif(s) (ou application(s)), tels que l’application 30. Le système d’exploitation 2 comporte, entre autres choses, un noyau 20. De manière classique, le noyau 20 comporte, entre autres choses, un module de contrôle d’entrée/sortie 21, un module de gestion des processus 22 et un module de gestion des appels système 23. Le module de gestion des processus 22 comporte, entre autres choses, un ordonnanceur 24. Celui-ci est associé à une liste des fils d’exécution 25 et à une file d’attente 26. Selon l’invention, le module de gestion des processus 22 du noyau comporte, en outre, un moteur d’exécution de tâches asynchrones 34. La réalisation par le moteur d’une tâche asynchrone doit être vue comme une machine à états, où un évènement cause une transition d’un état initial vers un état final de l’ensemble des états possibles de la tâche asynchrone, l’état final étant l’état « tâche terminée ». Le moteur 34 est associé à une liste de tâches asynchrones 35 et à des zones mémoire 36 dédiées. La liste de tâches asynchrones 35 indique l’ensemble des tâches asynchrones en cours d’exécution, et, pour chaque tâche, l’état d’exécution courant dans laquelle se trouve cette tâche, et l’évènement attendu pour effectuer une transition de l’état courant vers un état suivant. Le moteur 34 ne gère pas une pile, mais une zone mémoire 36 par tâche asynchrone à réaliser. Cette zone mémoire permet au moteur de stocker les valeurs des variables de la tâche asynchrone en cours de réalisation. La zone mémoire associée à une tâche asynchrone est de taille définie. Pour des raisons de clarté, sur la , la liste 25, la file 26, la liste 35 et des zones mémoires 36 sont représentées dans les modules 24 et 34, mais il s’agit bien de structures dans la mémoire de l’ordinateur. La manière de programmer un appel système bloquant dans le noyau selon l’invention est donnée dans la tableau suivant relatif à la partie du code source du noyau pour l’exemple de l’appel système « sys_sleep » en utilisant le langage de programmation Rust (« marque déposée »): fn sys_sleep T : ContextTrait >( ctx : & 'static mut T ) { // Entrées de l’appel système. Les paramètres d’entrée sont décodés. let now = crate :: timer :: GTimer :: now (); let duration ctx . syscall_in :: sys :: Sleep >(). duration ; let alarm = now . duration ; // Blocage du thread en cours d’exécution. let kernel = Sefl :: kernel_mut (); let th = kernel . threads . block_running (); let tid = th . read (). id (); // Lancer une tâche asynchrone pour gérer l'appel système bloquant. Le code suivant sera exécuté par le moteur. crate :: tasks :: spawn ( tid , async move { kernel . delay . deadline ( alarm ) . await ; kernel . threads . unblock ( th ); let res = crate :: timer :: GTimer :: now () - now ; ctx :: syscall_out :: sys :: Sleep >( & res ); }); } Dans cet exemple, l’appel système « sys_sleep » a pour but de mettre en attente un fil d’exécution appelant pendant un temps donné. Cette fonction contient le blocage du fil d’exécution en cours (instruction « kernel.threads.block_running() »). Cette fonction contient ensuite la fonction création d’une tâche asynchrone (« crate::tasks::spawn »). L’exécution de cette fonction conduit à la création d’une tâche asynchrone (instruction « async move »). La tâche asynchrone est exécutée par la moteur 34. C’est dans cette tâche asynchrone que se trouve le détail des instructions de l’appel système en tant tel. Elle comporte les évènements attendus pour faire avancer l’exécution de ces instructions, comme par exemple ici l’attente de la survenue du temps écoulé (instruction « .await »). La tâche asynchrone comporte également les instructions à exécuter, comme par exemple ici les instructions pour finaliser la tâche asynchrone lorsque l’évènement attendu est arrivé (« res = crate::timer::GTimer::now() – now »). La tâche asynchrone comporte finalement le retour de la fonction système (« ctx::syscall_out:: ( &res ) ») Ainsi, dans le code source du tableau ci-dessus, qui est une expression extrêmement synthétique des instructions du noyau lors d’un appel système bloquant, on constate qu’une tâche asynchrone comporte, en plus des instructions de l’appel système en tant que tel (c’est-à-dire le code du service rendu par le noyau), la machine à états caractérisant l’avancement de l’exécution de la tâche asynchrone, ainsi que la gestion du réveil du fil d’exécution appelant. Comme illustré sur la , le procédé 100 de gestion d’un appel système par le noyau 20 s’effectue de la manière suivante. Dans une étape 110, alors qu’un fil d’exécution, par exemple d’un processus de l’application 30, est en cours d’exécution par le processeur dans le mode non-privilégié sur une pile non-privilégiée dédiée au fil d’exécution, ce dernier fait un appel système, cet appel système étant identifié par un identifiant. Dans une étape 120, du fait de cet appel système, le processeur 11 bascule du mode non-privilégié vers le mode privilégié pour la réalisation par le noyau 22 des instructions de l’appel système. La sauvegarde du contexte non-privilégié du fil d’exécution est réalisée dans la pile non-privilégiée du fil d’exécution. Dans l’étape 130, le module de gestion des appels système 23 récupère l’identifiant de l’appel système et détermine, sur la base de cet identifiant, s’il s’agit d’un appel système du type non-bloquant ou d’un appel système du type bloquant. Dans le premier cas, l’appel système non-bloquant est géré de manière classique, c’est-à-dire que les instructions de l’appel système sont exécutées par le processeur sur la pile privilégiée unique du noyau et retourne l’appel système au fil d’exécution appelant (étape 140). Du fait de ce retour à l’appel système, le processeur bascule du mode privilégié vers le mode non-privilégié (étape 150) pour poursuivre l’exécution des instructions du fil d’exécution appelant (étape 160), en tenant compte du résultat de l’appel système et des informations présentes dans la pile non-privilégiée du fil d’exécution. Dans le second cas, dans l’étape 170, sur requête du module 23, l’ordonnanceur 24 place le fil d’exécution appelant dans l’état « waiting » dans la liste 25. Il enlève le fil d’exécution appelant de la file d’attente 26. Parallèlement, dans l’étape 180, le module 23 crée une tâche asynchrone pour gérer cette mise en attente du fil d’exécution appelant. La création d’une tâche asynchrone consiste à définir la machine à états associée à cette tâche asynchrone et à enregistrer une nouvelle entrée dans la liste des tâches asynchrone 35, définissant l’état courant de la tâche asynchrone et l’évènement attendu pour faire évoluer cet état. Une zone mémoire 36 est réservée pour la tâche asynchrone. Puis, dans l’étape 190, le moteur est exécuté. Il exécute le contenu de la section « async» de la tâche asynchrone sur la pile noyau en utilisant les informations nécessaires à l’exécution de la tâche asynchrone stockées dans la zone de la mémoire de l’ordinateur dédiée au moteur. L’exécution de la tâche avance jusqu’à un état d’exécution bloquant nécessitant la survenue d’un évènement attendu. Dans l’exemple précédent, ceci correspond à l’exécution de la tâche jusqu’à l’instruction « .await » (cf. tableau ci-dessous). L’instruction « .await » indique qu’un évènement est attendu. S’il n’est pas encore survenu, l’exécution de la tâche asynchrone est bloquée. Le moteur met à jour la liste 35 en indiquant l’état courant de la tâche et l’évènement attendu pour pouvoir reprendre l’exécution de la tâche. Le processeur peut alors exécuter le fil d’exécution suivant dans la file d’attente 26 ou d’autres tâches du noyau (en utilisant la pile privilégiée). En particulier, dans une étape 210, suite à une interruption indicative de la survenue d’un nouvel évènement (étape 200), le moteur est exécuté sur la pile privilégiée du noyau pour parcourir la liste des tâches 35 afin de vérifier si ce nouvel évènement correspond à l’évènement attendu par l’une ou l’autre des tâches asynchrones de la liste 35. Lorsque cet évènement correspond à l’évènement attendu par la tâche asynchrone associée à l’appel système de l’étape 110, alors dans l’étape 220, l’exécution de cette tâche asynchrone par le noyau est reprise de manière à réaliser la transition de l’état d’exécution courant à l’état d’exécution suivant. Plus précisément, le moteur poursuit l’exécution du contenu de la section « async» de la tâche asynchrone, jusqu’à atteindre une autre instruction « .await ». A l’étape 230, le nouvel état atteint par la tâche asynchrone est testé pour savoir s’il correspond à l’état « tâche terminée ». Dans la négative, les étapes 190 à 230 sont itérées. En revanche, si à l’étape 230, il s’avère que l’état de la tâche asynchrone est l’état « tâche terminée », alors, dans l’étape 240, le noyau exécute la fin de la section « async» de la tâche asynchrone de manière à la finaliser. Puis, cette tâche est détruite en la retirant de la liste 35. La suppression de la tâche de la liste 35 étant constatée par le module 23, dans l’étape 250, le moteur retourne l’appel système en mettant à jour le contexte d’exécution du fil d’exécution appelant avec le résultat de l'exécution de la tâche asynchrone. Le moteur modifie l’état du fil d’exécution appelant en le basculant vers l’état « Ready ». Dans l’étape 260, le fil d’exécution appelant étant dans l’état « Ready », l’ordonnanceur peut le replacer dans la liste d’attente 36 pour poursuivre l’exécution de ce fil d’exécution par le processeur dans le mode non-privilégié en tenant compte des informations présentes dans la pile non-privilégiée de ce fil d’exécution. Ainsi, les fils d’exécution bloqués sont gérés par le moteur d’exécution de tâches asynchrones. L’ordonnanceur du noyau gère l’exécution des fils d’exécution non bloqués. Les fils d’exécution bloqués ne sont pas de son ressort. Ainsi, le moteur, lorsqu’il est appelé par le noyau, gère l’exécution des fils d’exécution bloqués jusqu’à leur déblocage. Le moteur consulte la liste des tâches asynchrones en cours et fait évoluer leur exécution. Si un événement attendu par une tâche asynchrone (suite à un « .await » dans le code du tableau ci-dessus) est survenu, cela permet au moteur de continuer à exécuter les instructions suivantes jusqu’à la fin de la tâche ou jusqu’à ce que la tâche soit de nouveau bloquée (i.e. présence d’un autre « .await « dans le code de la tâche). La illustre le principe de la programmation asynchrone de manière générale, ). Il montre l’exécution de deux fonctions asynchrones appelées séquentiellement dans un même fil d’exécution. On considère qu’un processus a besoin de deux données, A et B, la donnée A étant obtenue par un premier appel système bloquant à une fonction fA effectué par un premier fil d’exécution du processus et la donnée B étant obtenue par un second appel système bloquant à une fonction fB effectué par un second fil d’exécution du processus. Le premier fil d’exécution du processus effectue l’appel système à la fonction fA. Le noyau place le premier fil d’exécution en attente (état « waiting ») tout en créant une première tâche asynchrone pour la réalisation par le moteur de la fonction fA. L’exécution du processus se poursuit, par exemple par l’élection du second fil d’exécution. Le second fil d’exécution du processus effectue l’appel système à la fonction fB. Le noyau place le second fil d’exécution en attente (état « waiting ») tout en créant une seconde tâche asynchrone pour la réalisation par le moteur de la fonction fB. Le premier fil d’exécution appelant reprend son exécution une fois que la tâche correspondant à l’appel à la fonction fA est terminée. Similairement, le second fil d’exécution appelant reprend son exécution une fois que la tâche correspondant à l’appel à la fonction fb est terminée. On constate que le processus disposera dans un temps plus court des données A et B que dans le cas par exemple où les deux appels systèmes sont gérés séquentiellement par le noyau. Un parallèle peut être dressé entre fil d’exécution / noyau selon la présente invention et utilisateur / serveur Web dans le domaine des communications internet. Un serveur Web traite en effet les requêtes de différents utilisateurs de manière asynchrone afin d’optimiser le nombre de connexions à chaque instant. Les avantages du noyau selon l’invention sont nombreux : - la programmation asynchrone peut être vue comme des tâches coopératives qui se partagent un même contexte d’exécution, notamment une pile privilégiée commune. - un gain en sureté puisque la gestion est réalisée automatiquement par le langage et le compilateur associé et non pas par le programmeur, réduisant ainsi le risque d’erreur. Il n’y a plus de problème de dimensionnement de la taille de la pile en mode privilégié. La zone mémoire est de taille prédéfinie et adaptée à la réalisation de la tâche asynchrone correspondante. Le noyau selon l’invention est donc synonyme d’un haut niveau de confiance. - un coût de développement réduit puisque le code source du noyau selon l’invention conserve l’aspect séquentiel (comme l’illustre le tableau ci-dessus), ce qui permet au programmeur de le lire facilement et de le mettre à jour aisément, participant à une réduction du coût de développement. De plus la gestion de l’état d’avancement des fils d’exécution bloqués est faite, non pas manuellement par le développeur, mais par le langage et le compilateur. - un gain en performance du fait de l’utilisation minimale de ressources mémoire (une seule pile privilégié) et l’utilisation optimale du CPU (pas de changement intempestif du contexte). - Tout le noyau (y compris le moteur d’exécution des taches asynchrones) utilise une seule et même pile privilégiée. Mais l’état des taches asynchrones est sauvegardé, non pas dans une pile dédiée (« Process Model ») ou dans des structures manuellement implémentées pas le développeur (« IRQ model ») mais dans une mémoire dédiée, qui est gérée automatiquement. La seule contrainte de la mise en œuvre de la présente invention est de disposer d’un compilateur supportant la programmation asynchrone pour pouvoir compiler le code source de manière à obtenir un code objet exécutable par un ordinateur. Procédé (100) de gestion d’un appel système, mis en œuvre par un noyau (20) d’un système d’exploitation (2) exécuté par un ordinateur, l’appel système ayant été émis par un fil d’exécution d’une application (30) exécuté par l’ordinateur, caractérisé en ce que, ledit noyau comportant un ordonnanceur (24) et un moteur d’exécution de tâches asynchrones (34), ledit procédé comporte les étapes de : a)- détermination (130) par le noyau si l’appel système est un appel système bloquant ; et, dans l’affirmative : b)- mise en sommeil (170) par le noyau du fil d’exécution ; c)- création (180) par le noyau d’une tâche asynchrone pour réaliser l’appel système, la tâche asynchrone étant équivalente une machine à états, une transition d’un premier état d’exécution vers un second état d’exécution étant initiée par un évènement attendu, et mise à jour par le noyau d’une liste de tâches asynchrones à exécuter par le moteur avec les informations relatives à la tâche asynchrone créée ; d)- exécution (190) par le moteur de la tâche asynchrone sur une pile du noyau en utilisant les informations de la zone mémoire relatives à la tâche asynchrone, jusqu’à atteindre un état d’exécution bloquant nécessitant un évènement attendu correspondant, l’exécution de la tâche asynchrone étant alors bloquée et la liste de tâches asynchrones mise à jour avec l’état d’exécution bloquant atteint et l’évènement attendu correspondant ; e)- lors de la survenue (200) de l’évènement attendu correspondant, reprise de l’exécution (220) par le moteur de la tâche asynchrone sur la pile du noyau de manière à effectuer la transition de l’état d’exécution bloquant vers un état d’exécution bloquant suivant ; f)- vérification (230) si l’état d’exécution bloquant suivant est un état d’exécution final de la tâche ; et dans l’affirmative, g)- finalisation (240) de l’exécution de la tâche asynchrone et suppression de la tâche asynchrone de la liste de tâches asynchrones à exécuter par le moteur ; et, h)- retour (250) par le noyau de l’appel système au fil d’exécution et réveil par le noyau du fil d’exécution. Procédé selon la revendication 1, dans lequel, lorsque l’étape de vérification (230) conduit à conclure que l’état d’exécution bloquant suivant n’est pas l’état d’exécution final de la tâche asynchrone, les étapes d), e) et f) sont itérées. Procédé selon la revendication 1 ou la revendication 2, comportant, lorsque le noyau détermine (130) que l’appel système reçu est un appel système non-bloquant, les étapes de : - exécution (140) par le noyau de l’appel système sur une pile du noyau ; et, - retour (150) par le noyau de l’appel système au fil d’exécution. Procédé selon l’une quelconque des revendications précédentes, dans lequel la mise en sommeil par le noyau du fil d’exécution consiste à basculer un état d’exécution du fil d’exécution d’un état « en cours d’exécution» à un état « en attente » et le réveil par le noyau du fil d’exécution consiste à basculer l’état d’exécution du fil d’exécution de l’état « en attente» à un état «prêt à être exécuté». Procédé selon l’une quelconque des revendications précédentes, dans lequel, entre la mise en œuvre des étapes d) et e), un autre fil d’exécution présent dans une file d’attente de l’ordonnanceur est exécuté. Procédé selon l’une quelconque des revendications précédentes, dans lequel, lors d’une interruption indicative de la survenue d’un nouvel évènement, le moteur est exécuté pour identifier la tâche asynchrone de la liste des tâches asynchrones pour laquelle le nouvel évènement constitue l’évènement attendu. Produit programme d’ordinateur comportant des instructions qui, lorsqu’elles sont exécutées par un processeur d’un ordinateur, munissent ledit ordinateur d’un noyau, caractérisé en ce que ledit noyau comporte un ordonnanceur et un moteur d’exécution de tâches asynchrones, ledit moteur de tâches asynchrones étant associé à une liste de tâches asynchrones à exécuter et une zone mémoire dédiée dans une mémoire de l’ordinateur, le noyau étant adapté, lors de la réception d’un appel système émis par un fil d’exécution d’une application exécutée par l’ordinateur, pour réaliser un procédé de gestion dudit appel système conforme à l’une quelconque des revendications 1 à 6. Produit programme d’ordinateur selon la revendication 7, dans lequel le noyau est associé à une unique pile noyau. Produit programme d’ordinateur selon l’une quelconque des revendications 7 à 8, résultant de la compilation d’un code source, ledit code source se présentant sous une forme séquentielle même pour les appels systèmes bloquants.