attendre bash-builtin brûle un CPU à 100 pour cent

16

Se produit au moins sur GNU bash version 4.3.42 x86_64 && GNU bash version 4.3.11 x86_64

J'utilise sleep & wait $!au lieu d'un simple sleeppour obtenir un interruptible sleeppar un signal (comme SIGUSR1 ). Mais il semble que le waitbash-builtin se comporte de manière étrange lorsque vous exécutez ce qui suit.

Terminal 1:

cat <(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
   )&

Terminal 2:

kill -10 /the pid of the subshell, printed by the previous command/

Terminal 1:

^C (ctrl + C)

Ensuite, j'obtiens le sous-shell qui brûle un processeur à 100%.

Terminal 1:

pkill -P $(pgrep -P $$)

Avez-vous une idée de la raison pour laquelle ce problème se produit?

NB : aucun problème ne se produit lorsque le cat <(/subshell/)n'est pas en arrière-plan.


Une autre façon de ressentir ce comportement

Terminal 1:

(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
)&

Terminal 2:

kill -10 /the pid of the subshell, printed by the previous command/

Terminal 1:

fg
^C (ctrl + C)

Ensuite, obtenez une coquille gelée.


Une troisième façon de ressentir ce comportement

Terminal 1:

(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
)

Terminal 2:

kill -10 /the pid of the subshell, printed by the previous command/

Terminal 1:

^C (ctrl + C)

Ensuite, obtenez une coquille gelée.

M89
la source
Pour déboguer cela, vous devez probablement construire Bash à partir de sources et savoir où il boucle (le casser avec un débogueur ou ajouter des instructions d'impression) et pourquoi il boucle.
Kaz
1
Étrange? Je ne peux pas reproduire cela ici, j'utilise bash 4.3.42 (1) -release (x86_64-pc-linux-gnu). Debian 8. Kernel 4.6.1-1. Je fais tous les tests que vous dites, mais le CPU fonctionne toujours normalement ... Je fais exactement comme vous dites, y compris le fg, puis CTRL + C.
Luciano Andress Martini
Je me souviens avoir lu que certaines choses liées aux intégrés et aux signaux ont changé en bash4.4, peut-être que cela pourrait être affecté ici.
phk
Bash 4.4.20 corrige un problème de spinloop waitqui ressemble beaucoup à ceci. J'ai été frappé par cela dans une boucle qui a engendré des sous-processus pour toujours. Cependant, j'ai testé votre scénario le 4.4.20 et c'était toujours un problème. Fait intéressant, lorsque j'ai attaché un débogueur sur une version que j'ai construite, je pouvais voir qu'il tournait en boucle, mais cela avait également pour effet de sortir de celui-ci, et la boucle recommencerait à produire un `` test ''. En d'autres termes: attacher le débogueur l'a empêché de tourner en boucle.
Halfgaar

Réponses:

1

Observations

  • ctrl+cenvoie SIGINTau processus fg dans le terminal 1
  • par conséquent, l'exécution kill -2 <PID> dans le terminal 2 équivaut ctrl+cà frapper dans le terminal 1
  • faire l'un des deux points ci-dessus avant d' exécuterkill -10 <PID> dans le Terminal 2 gère SIGINTcorrectement
  • le faire après l' exécution kill -10 <PID>dans le Terminal 2 (envoi de signalSIGUSR1 ) ne se gère pas SIGINTcorrectement et conduit au comportement problématique
  • Remplacement kill -2 <PID>dans le terminal 2 ( SIGINT) par kill -15 <PID>(SIGTERM ) ou kill -9 <PID>( SIGKILL) conduit toujours à une gestion correcte du signal.
  • l'exécution kill -10 <PID>dans le Terminal 2 interrompt lawait intégrée mais ne quitte pas la boucle car elle testest immédiatement imprimée après que le signal SIGUSR1est piégé et la boucle continue.
  • L'envoi SIGINTsort de la boucle d'exécution et fige le shell ou il n'interrompt jamaiswait et reste en attente / gelé.

Conclusion

SIGINTn'est pas acheté et géré correctement ou il est ignoré après le piégeage manuel SIGUSR1ou peut-être tout autre piégeage défini par l'utilisateur. Cela signifie que le processus existe toujours et c'est pourquoi il mange / chauffe le CPU ou gèle le shell. Exécutionkill -15 <PID> ou à kill -9 <PID>partir du terminal 2 termine / tue le processus et vous redonne le contrôle sur le terminal 1 et détend votre processeur.

Pourquoi ce problème se produit, reste un mystère, mais j'espère que quelqu'un pourra expliquer exactement ce qui se passe réellement derrière les rideaux.

Neni
la source