C'est le terminal (pilote) qui intercepte le ^C et le traduit en un signal envoyé au processus attaché (qui est le shell) stty intr ^B
demanderait au pilote du terminal d'intercepter un ^B à la place. C'est également le pilote de terminal qui renvoie le ^C au terminal.
Le shell est juste un processus qui se trouve à l'autre bout de la ligne et reçoit son stdin de votre terminal via le pilote de terminal (tel que /dev/ttyX), et ses stdout (et stderr) sont également attachés au même tty .
Notez que (si l'écho est activé) le terminal envoie les frappes à les deux le processus (groupe) et retour au terminal. La commande stty n'est qu'un wrapper autour des ioctl()s pour le pilote tty pour les processus « contrôlant » tty.
MISE À JOUR :pour démontrer que le shell n'est pas impliqué, j'ai créé le petit programme suivant. Il doit être exécuté par son shell parent via exec ./a.out
(il semble qu'un shell interactif bifurquera un shell fille, de toute façon) Le programme définit la clé qui génère le SIGINTR sur ^B, désactive l'écho et attend ensuite l'entrée de stdin.
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
int thesignum = 0;
void handler(int signum);
void handler(int signum)
{ thesignum = signum;}
#define THE_KEY 2 /* ^B */
int main(void)
{
int rc;
struct termios mytermios;
rc = tcgetattr(0 , &mytermios);
printf("tcgetattr=%d\n", rc );
mytermios.c_cc[VINTR] = THE_KEY; /* set intr to ^B */
mytermios.c_lflag &= ~ECHO ; /* Dont echo */
rc = tcsetattr(0 , TCSANOW, &mytermios);
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc );
printf("Setting handler()\n" );
signal(SIGINT, handler);
printf("entering pause()\n... type something followed by ^%c\n", '@'+THE_KEY );
rc = pause();
printf("Rc=%d: %d(%s), signum=%d\n", rc, errno , strerror(errno), thesignum );
// mytermios.c_cc[VINTR] = 3; /* reset intr to ^C */
mytermios.c_lflag |= ECHO ; /* Do echo */
rc = tcsetattr(0 , TCSANOW, &mytermios);
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc );
return 0;
}
intr.sh :
#!/bin/sh
echo $$
exec ./a.out
echo I am back.
Le shell fait écho à tout ce que vous tapez, donc lorsque vous tapez ^C
, cela aussi est répercuté (et dans votre cas intercepté par votre gestionnaire de signal). La commande stty -echo
peut vous être utile ou non selon vos besoins/contraintes, consultez la page de manuel de stty pour plus d'informations.
Bien sûr, beaucoup plus se passe à un niveau inférieur, à tout moment vous communiquez avec un système via des pilotes de périphériques (tels que le pilote de clavier que vous utilisez pour générer le signal ^ C et le pilote de terminal qui affiche tout) sont impliqués. Vous pouvez creuser encore plus profondément au niveau du langage assembleur/machine, des registres, des tables de recherche, etc. Si vous voulez un niveau de compréhension plus détaillé et approfondi, les livres ci-dessous sont un bon point de départ :
La conception du système d'exploitation Unix est une bonne référence pour ce genre de choses. Deux autres références classiques :Unix Programming Environment et Advanced Programming in the UNIX Environment
Bon résumé ici dans cette question SO Comment Ctrl-C termine-t-il un processus enfant ?
"lorsque vous exécutez un programme, par exemple find
, la coque :
- la fourche shell elle-même
- et pour l'enfant, définissez la gestion du signal par défaut
- remplacer l'enfant par la commande donnée (par exemple par find)
- lorsque vous appuyez sur CTRL-C, le shell parent gère ce signal mais l'enfant le recevra - avec l'action par défaut - terminer. (l'enfant peut également implémenter la gestion du signal)"