Qu’est-ce que cela signifie de dire “le kernel Linux est préemptif”?

J’ai lu que le kernel Linux est préemptif, ce qui est différent de la plupart des kernelx Unix. Alors, qu’est-ce que cela signifie vraiment pour un kernel d’être préemptif?

Certaines analogies ou exemples seraient meilleurs que de simples explications théoriques.

Imaginez la vue simple du multitâche préemptif. Nous avons deux tâches utilisateur qui fonctionnent toutes les deux sans utiliser d’E / S ou d’appels au kernel. Ces deux tâches ne doivent rien faire de spécial pour pouvoir fonctionner sur un système d’exploitation multitâche. Le kernel, généralement basé sur une interruption de timer, décide simplement qu’il est temps pour une tâche de faire une pause pour en laisser une autre s’exécuter. La tâche en question ignore complètement que quelque chose est arrivé.

Cependant, la plupart des tâches font des requêtes occasionnelles du kernel via syscalls. Lorsque cela se produit, le même contexte utilisateur existe, mais le processeur exécute le code du kernel au nom de cette tâche.

Les kernelx Linux plus anciens ne permettraient jamais la préemption d’une tâche alors qu’il était occupé à exécuter du code du kernel. (Notez que les opérations d’E / S reprennent toujours volontairement leur planification. Je parle d’un cas où le code du kernel a des opérations nécessitant beaucoup de ressources processeur, comme le sorting d’une liste.)

Si le système permet à cette tâche d’être préemptée pendant qu’il exécute le code du kernel, alors nous avons ce qu’on appelle un “kernel préemptif”. Un tel système est immunisé contre les retards imprévisibles qui peuvent être rencontrés lors des appels système. Il peut donc être mieux adapté aux tâches embarquées ou en temps réel.

Par exemple, si sur un processeur particulier, deux tâches sont disponibles, l’autre prend un appel système qui prend 5 ms et l’autre est une application de lecteur MP3 qui doit alimenter le canal audio toutes les 2 ms.

L’argument contre la préemption est que tout le code du kernel qui pourrait être appelé dans le contexte de la tâche doit pouvoir survivre à la préemption – par exemple, un code de pilote de périphérique médiocre peut être mieux s’il est capable d’effectuer une opération avant permettant à une autre tâche de s’exécuter sur ce processeur. (Avec les systèmes multi-processeurs la règle plutôt que l’exception de nos jours, tout le code du kernel doit être ré-entrant, de sorte que l’argument n’est plus aussi pertinent aujourd’hui.) la latence, peut-être que la préemption est inutile.

Un compromis est CONFIG_PREEMPT_VOLUNTARY, qui permet un basculement de tâche à certains points du kernel, mais pas partout. S’il n’y a qu’un petit nombre d’endroits où le code du kernel pourrait s’enliser, c’est un moyen peu coûteux de réduire la latence tout en gardant la complexité gérable.

Avant Linux kernel version 2.5.4, Linux Kernel n’était pas préemptif, ce qui signifie qu’un processus s’exécutant en mode kernel ne peut pas être retiré du processeur tant qu’il ne quitte pas lui-même le processeur ou qu’il attend que certaines opérations de sortie soient terminées.

En général, un processus en mode utilisateur peut entrer en mode kernel en utilisant les appels système. Auparavant, lorsque le kernel n’était pas préemptif, un processus de priorité inférieure pouvait en priorité inverser un processus de priorité plus élevée en lui refusant l’access au processeur en appelant plusieurs fois les appels système et en restant en mode kernel. Même si le créneau horaire du processus de priorité inférieure expirait, il continuerait à s’exécuter jusqu’à ce qu’il termine son travail dans le kernel ou qu’il abandonne volontairement le contrôle. Si le processus prioritaire en attente d’exécution est un éditeur de texte dans lequel l’utilisateur est en train de taper ou un lecteur MP3 prêt à recharger son tampon audio, le résultat est une mauvaise performance interactive. De cette façon, le kernel non préemptif était un inconvénient majeur à cette époque.

Les kernelx unix traditionnels avaient un verrou unique, qui était tenu par un thread pendant que le code du kernel était en cours d’exécution. Par conséquent, aucun autre code du kernel ne peut interrompre ce thread.

Cela a facilité la conception du kernel, puisque vous saviez que lorsqu’un thread utilisait des ressources du kernel, il n’y en avait pas d’autre. Par conséquent, les différents threads ne peuvent pas se gâter mutuellement.

Dans les systèmes monoprocesseurs, cela ne pose pas trop de problèmes.

Cependant, dans les systèmes multiprocesseurs, plusieurs threads situés sur des processeurs ou des cœurs différents peuvent tous exécuter le code du kernel en même temps. Cela signifie que, selon le type de charge de travail, vous pourriez avoir beaucoup de processeurs, mais tous passent le plus clair de leur temps à attendre les uns les autres.

Dans Linux 2.6, les ressources du kernel étaient divisées en unités beaucoup plus petites, protégées par des verrous individuels, et le code du kernel était examiné pour s’assurer que les verrous n’étaient conservés que pendant l’utilisation des ressources correspondantes. Ainsi, différents processeurs doivent désormais attendre les uns les autres s’ils veulent accéder à la même ressource (par exemple, une ressource matérielle).

La préemption permet au kernel de donner l’IMPRESSION du parallélisme: vous n’avez qu’un seul processeur (disons il ya dix ans), mais vous avez l’impression que tous vos processus fonctionnent simultanément. Cela est dû au fait que le kernel pré-exécute l’exécution d’un processus pour le donner au suivant (peut-être en fonction de leur priorité).

EDIT Les kernelx non préemptifs attendent que les processus rendent la main (c.-à-d. Pendant les appels système), donc si votre processus calcule beaucoup de données et n’appelle aucun type de fonction de yield , les autres processus ne pourront pas s’exécuter. exécuter leurs appels. De tels systèmes sont censés être coopératifs car ils demandent la coopération des processus pour assurer l’équité du temps d’exécution

EDIT 2 L’objective principal de la préemption est d’améliorer la réactivité du système entre plusieurs tâches, ce qui est bon pour les utilisateurs finaux, tandis que les serveurs veulent obtenir le meilleur rendement possible, donc ils n’en ont pas besoin: (à partir de la configuration du kernel Linux)

  • Noyau préemptible (desktop à faible latence)
  • Préemption volontaire du kernel (bureau)
  • Pas de préemption forcée (serveur)

Cela signifie que le planificateur du système d’exploitation est libre de suspendre l’exécution des processus en cours d’exécution pour donner au processeur un autre processus à tout moment. La méthode normale consiste à donner à chaque processus qui attend le processeur un «quantum» de temps CPU à exécuter. Une fois qu’il a expiré, le planificateur reprend le contrôle (et le processus en cours ne peut pas l’éviter) pour donner un autre quantum à un autre processus.

Cette méthode est souvent comparée au multitâche coopératif, dans lequel les processus conservent le processeur pendant tout le temps dont ils ont besoin, sans être interrompus, et pour laisser les autres applications s’exécuter, ils doivent appeler explicitement une sorte de fonction “rendement”; Naturellement, pour éviter de donner l’impression que le système est bloqué, les applications les plus efficaces produiront souvent le processeur. Cependant, s’il y a un bogue dans une application (par exemple, une boucle infinie sans appels de rendement), le système entier sera bloqué, car le programme défectueux conserve complètement le processeur.

Presque tous les systèmes d’exploitation récents utilisent le multitâche préemptif, qui, même s’il est plus coûteux en termes de ressources, est généralement plus stable (il est plus difficile pour une application défectueuse d’accrocher tout le système, car le système d’exploitation est toujours sous contrôle). D’autre part, lorsque les ressources sont restreintes et que l’application est censée se comporter correctement, le multitâche coopératif est utilisé. Windows 3 était un système d’exploitation multitâche coopératif; Un exemple plus récent peut être RockBox, un remplacement de firmware PMP opensource.

Le kernel Linux est monolithique et donne un laps de temps de calcul séquentiel à tous les processus en cours d’exécution. Cela signifie que les processus (par exemple, les programmes) ne sont pas exécutés simultanément, mais qu’ils reçoivent régulièrement un délai pour exécuter leur logique. Le principal problème est que la logique peut prendre plus de temps pour se terminer et empêcher le kernel de consacrer du temps au processus suivant. Cela se traduit par des “décalages” du système.

Un kernel pré-initial permet de changer de contexte . Cela signifie qu’il peut arrêter un processus de “suspension” même s’il n’est pas terminé, et donner le temps de calcul au processus suivant, comme prévu. Le processus de “suspension” continuera à s’exécuter lorsque son heure sera arrivée sans aucun problème.

En pratique, cela signifie que le kernel a la capacité de réaliser des tâches en temps réel, ce qui est particulièrement intéressant pour l’enregistrement et l’édition audio.

La solution de studio ubuntu regroupe un kernel préemptif ainsi qu’un lot de logiciels gratuits de qualité dédiés à l’édition audio et vidéo.

Je pense que c’est devenu préemptif de 2.6. préemptif signifie lorsqu’un nouveau processus est prêt à fonctionner, le processeur sera alloué au nouveau processus, il n’a pas besoin que le processus en cours soit coopératif et abandonne le processeur.

Le kernel Linux est préemptif signifie que le kernel prend en charge la préemption.

Par exemple, deux processus P1 (priorité supérieure) et P2 (priorité inférieure) effectuent des appels système en lecture et fonctionnent en mode kernel. Supposons que P2 soit en cours d’exécution et soit en mode kernel et que P2 soit programmé pour s’exécuter.

Si la préemption du kernel est disponible, alors la préemption peut se produire au niveau du kernel, c’est-à-dire que P2 peut être préempté et que le P1 peut continuer à s’exécuter.

Si la préemption du kernel n’est pas disponible, puisque P2 est en mode kernel, le système attend simplement que P2 soit terminé, puis