# Interruption (informatique)

En informatique, une interruption est une suspension temporaire de l'exécution d'un programme informatique par le microprocesseur afin d'exécuter un programme prioritaire (appelé service d'interruption).
Dans son acception la plus stricte, le terme ne désigne que des interruptions dont l'exécution est provoquée par des causes externes au programme : avancement d'une horloge, signalisation de la complétion d'un transfert de données, positionnement d'une tête de lecture/écriture, etc. Cependant, on l'utilise aussi pour désigner des exceptions, c'est-à-dire des arrêts provoqués par une condition exceptionnelle dans le programme (instruction erronée, accès à une zone mémoire inexistante, calcul arithmétique incorrect, appel volontaire au système d'exploitation, etc.). On parle alors parfois d'interruptions asynchrones pour désigner celles résultant d'un événement externe, et d'interruptions synchrones pour désigner les exceptions provoquées par le déroulement du programme. Ces dernières étaient nommées déroutements en terminologie CII-Honeywell-Bull.

## Fonctionnement

Lors d'une interruption, le processeur enregistre tout ou une partie de son état interne, généralement dans la pile système, et exécute ensuite une routine d'interruption, généralement en suivant les directives d'une table indiquant pour chaque type d'interruption, le sous programme à exécuter.
Une fois le traitement de l'interruption terminé, la routine se finit normalement par une instruction de retour d'interruption, qui restaure l'état enregistré et fait repartir le processeur de l'endroit où il avait été interrompu. Dans certains cas, la routine d'interruption modifie l'adresse de retour, notamment pour effectuer des commutations de tâches.
Lors du fonctionnement de certaines parties du système d'exploitation, il peut être nécessaire d'interdire les interruptions, soit parce que celles-ci perturberaient un compte serré du temps, soit parce que des structures de données sont en cours de modification (on réalise ainsi une sorte de verrou d'exclusion mutuelle dans un système mono-processeur). Aussi, on peut généralement bloquer (on dit souvent masquer) les interruptions. Dans la plupart des systèmes, les interruptions bloquées sont accumulées, c'est-à-dire qu'elles sont exécutées dès qu'elles sont démasquées. Cependant, pour chaque type d'interruption, le compteur d'interruptions en attente se réduit souvent à un simple drapeau ; si cela peut ne pas être gênant si l'interruption signale des données en attente sur un périphérique, cela peut cependant occasionner des mauvais comptes si l'interruption déclenche l'incrémentation d'une horloge, si les interruptions sont bloquées pour une durée supérieure à la période de l'horloge.
Sur certains systèmes, il existe une interruption non masquable, généralement dédiée au signalement d'une « erreur catastrophique » pour le système (par exemple, détection d'une erreur mémoire par code correcteur d'erreurs).
Les interruptions peuvent par ailleurs être hiérarchisées suivant des priorités. Une interruption de priorité supérieure est prise en compte lors de la fin du traitement d'une autre interruption, mais une interruption de priorité inférieure est mise en attente.
Ainsi, sur une machine comme l'IBM 1130, les priorités maximales étaient données à la lecture d'une colonne sur le lecteur de cartes (tout délai à la traiter pouvant impliquer une perte de données) et à la frappe d'une touche sur la console de pupitre (car la machine, surtout dans sa version temps réel 1800, devait être très réactive). Les unités de sortie pouvant attendre sans dommage, comme l'imprimante, avaient une priorité moins élevée.

## Usages

On utilise les interruptions, principalement dans deux buts :
* permettre des communications non bloquantes avec des périphériques externes ;
* commuter entre les tâches dans un ordonnanceur.
Un autre usage, celui-là non prévu initialement, est l'introduction de malversations : lors de la restauration du contexte, si le contenu de la zone de sauvegarde a été altéré depuis l'appel (c'est le cas si l'interruption ou le déroutement provoque en mode maître une altération du contenu de la zone de sauvegarde ou de la pile), le contexte restauré sera totalement différent du contexte d'appel, et pourra passer la main à des suites d'instructions hostiles. Les systèmes comme le matériel des microprocesseurs s'efforcent de plus en plus de rendre ces tâches difficiles pour les pirates, mais la faille - bien que fortement réduite aujourd'hui - continue dans une certaine mesure à exister.

### Entrées-sorties

Lorsque le processeur interroge un périphérique (disque dur, port de communication, etc.), il y a en général des délais avant que les données ne puissent être obtenues ou transmises. La solution la plus simple est simplement d'attendre les données ou la fin de la transmission en bouclant répétitivement sur un test (attente active, ou polling). Malheureusement, cela bloque tout autre programme en cours, ce qui est gênant sur un système multi-tâche. Sur les systèmes modernes, on préfère donc généralement un fonctionnement par interruption : le périphérique signale par une interruption qu'il est prêt à émettre, ou que les données ont été transmises ou reçues, et une routine fait le traitement nécessaire. Pour les périphériques rapides (disque dur, USB...), on combine généralement ce procédé avec l'accès direct en mémoire (DMA) : des blocs de données sont lus ou écrits en mémoire par le contrôleur sans intervention du processeur, qui n'intervient qu'en début et en fin de transfert.
L'usage d'interruptions par rapport au polling permet aussi des économies d'énergie et un moindre échauffement : les microprocesseurs actuels possèdent généralement une instruction arrêtant le microprocesseur en attente d'une interruption.

### Multi-tâche

On utilise également les interruptions pour commuter les tâches dans les systèmes multi-tâches. Généralement, une interruption périodique est déclenchée par une horloge (souvent 100 ou 1 000 Hz), et l'ordonnanceur est alors mis en action. Il peut commuter les tâches en modifiant la tâche de retour de l'interruption.

## Remarques
### Priorité des interruptions

De façon tout à fait contre-intuitive, c'était dans les premiers systèmes les périphériques les plus lents qui étaient affectés des priorités d'interruption les plus hautes. En effet :
* Ces interruptions étant peu nombreuses à cause de cette lenteur, leur haute priorité n'avait que peu d'impact sur la charge ;
* Ces périphériques pouvaient être synchrones (interruption liée à une colonne de carte perforée sous le lecteur, par exemple) et exiger un traitement aussi immédiat que possible.
Les priorités étaient attribuées en ordre décroissant ainsi : pupitre de commande, lecteur de cartes, imprimante, disque.
Les interfaces graphiques n'ont plus permis que le traitement de l'écho d'un caractère soit traité par une routine de haute priorité (le positionnement de cet écho, en multifenêtrage et avec des polices de taille variable, nécessite en effet plusieurs dizaines de milliers d'opérations), et rendent paradoxalement ces interfaces bien moins réactives dans les situations de forte charge machine, en dépit de l'usage de processeurs considérablement plus puissants.

### Interruptions contre polling

Les interruptions ont, au départ, représenté un énorme progrès par rapport à l'attente active (boucle d'attente) de périphériques : en effet, l'unité centrale n'était pas obligée de perdre du temps dans des boucles d'attente et n'était sollicitée par les différents périphériques que lorsque quelque chose était à faire.
L'apparition de périphériques très rapides comme les SSD qui demandent des dizaines de milliers d'interventions par seconde a sensiblement changé la donne : les sollicitations de l'unité centrale deviennent si nombreuses que les sauvegardes d'états nécessitées par les interruptions deviennent elles-mêmes une source de contre-performance. Le noyau 2.6.32 de Linux permet donc de basculer lorsque nécessaire du mode interruption au mode attente active (en anglais polling) pour ce type de périphérique.