Salut je bricole du C dans mon garage.
Mon but c'est d'empécher l'utilisateur d'un programme de faire un Ctrl + C pendant une tâche critique.
Donc j'ai trouvé la fonction sigprocmask qui permet de manipuler(edit : bloquer) certains signaux du système.
Ca fonctionne bien mais je ne comprend pas pourquoi je récupère la main sur le terminal malgrès que j'ai mis un blockage du signal SIGHUP.
Par contre l'execution n'est pas interrompu et c'est ce que je voulais.
# Un bout de code ???
Posté par totof2000 . Évalué à 2.
Tout est dans le titre.
[^] # Re: Un bout de code ???
Posté par n0wic . Évalué à 1. Dernière modification le 24 octobre 2015 à 19:13.
Alors je fais comme cà :
dans mon application :
Heu c'est peut être plus clair sans les commentaires.
[^] # Re: Un bout de code ???
Posté par n0wic . Évalué à 1.
Je ne peu plus améliorer la mise en page, si un magicien avec pouvoirs passe par là pour me permettre d'arranger ca ca serait sympa .
[^] # Re: Un bout de code ???
Posté par NeoX . Évalué à 4.
l'ouverture etait bonne ```C
mais il manquait le saut de ligne AVANT, et la fermeture au bout de ton code avec ```
j'ai corrigé ca.
[^] # Re: Un bout de code ???
Posté par n0wic . Évalué à 1.
merci
[^] # Re: Un bout de code ???
Posté par benja . Évalué à 3.
1) il peut-être intéressant de vérifier le retour de sigprocmask (hum…)
2) " A signal may be blocked, which means that it will not be delivered
until it is later unblocked. Between the time when it is generated and
when it is delivered a signal is said to be pending."
(de man 7 signal) : es-tu sur que ton programme est bien intérompu entre tes 2 appels à sigprocmask ?
3) pour ignorer un signal tu es du coup obligé d'écrire ton handler…
À partir de ce moment, je te conseille d'ouvrir un bouquin de programmation unix, car entre les threads, le polling d'évenements, l'éxéuctions de sous-processus, etc, il y a pas mal de subtilités (de la à dire que les programmes qui les gère correctement ne font pas légions, il n'y a qu'un pas…) Les signaux sont souvent considérés comme une moins bonne invention d'UNIX, à mon avis, à juste titre :-)
[^] # Re: Un bout de code ???
Posté par benja . Évalué à 4.
By the way, c'est uniquement de SIGINT dont tu as besoin pour intercepter le ctrl-c… Tout spécifier "en espérant que ça marche" démontre simplement que tu n'as pas compris l'utilisation des signaux. Ceux-ci ne sont uniquement qu'un mécanisme de notification asynchrone et préemptif (si tu comprends pourquoi ces deux mots sont importants, alors c'est que tu comprends comment fonctionnent les signaux) du noyau à l'attention des processus. Il va de soit que chaque signal a son utilité spécifique et doit être traité comme il se doit.
[^] # Re: Un bout de code ???
Posté par Krunch (site web personnel) . Évalué à 2.
Non.
sigpending(3) nous dit clairement :
Par contre ça se fait avec sigaction, pas sigprocmask.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Un bout de code ???
Posté par benja . Évalué à 1.
Bien vu.
[^] # Re: Un bout de code ???
Posté par Krunch (site web personnel) . Évalué à 2.
SIG_IGN et SIG_DFL ne sont pas des arguments valides pour sigaddset. Je n'arrive pas à reproduire le comportement que tu décris mais si je retire ces deux lignes, j'ai le comportement que tu recherches.
Cela dit, tu n'a besoin que de bloquer SIGINT pour faire ce que tu veux. D'un autre côté, selon ton but ultime, c'est peut-être insuffisant ou il y a peut-être d'autres moyens plus propres.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
# autre signal à traiter ?
Posté par nono14 (site web personnel) . Évalué à 2.
Tout est dans le titre
Système - Réseau - Sécurité Open Source - Ouvert à de nouvelles opportunités
# désactiver ctrl-c
Posté par Krunch (site web personnel) . Évalué à 2.
Plutôt que d'ignorer SIGINT, tu pourrais peut-être dire au terminal d'ignorer Ctrl-C pour qu'il ne génère pas le signal. Ça se fait avec tcsetattr(IGNBRK) en gros. Voire termios(3).
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: désactiver ctrl-c
Posté par benja . Évalué à 2.
Bonne idée ça que de l'envoyer dans un domaine encore plus dégeux que la gestion des signaux, à savoir la gestion des tty :-)
[^] # Re: désactiver ctrl-c
Posté par Krunch (site web personnel) . Évalué à 2.
L'API est peut-être moins joli mais c'est plus difficile de l'utiliser de manière incorrect.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: désactiver ctrl-c
Posté par fcartegnie . Évalué à 10.
Le plus simple 'est de retirer du lavier la touhe assoiée dans ontrol+, ou bien la touhe ontrol elle même,
omme à, plus possible de taper la ombinaison fautive !
Je teste en e moment même !
[^] # Re: désactiver ctrl-c
Posté par n0wic . Évalué à 2.
et a se pakage très bien :
# exploiter le Ctrl+C plutôt que de le masquer ?
Posté par flavien75 . Évalué à 4.
Personnellement j'utilise plutôt ce code :
Ça permet au programme de balancer des "attend un peu que je finisse" tout en permettant à l'utilisateur de marteler Ctrl+C pour tuer violemment le programme.
Accessoirement ce bout de code fonctionne aussi bien sous windows que sous Linux.
Les vrais naviguent en -42
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par Krunch (site web personnel) . Évalué à 4.
fprintf(3) et exit(2) ne peuvent pas être utilisés de manière sûre dans une fonction de gestion de signal. Voire signal(7).
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par flavien75 . Évalué à 1.
Bien vu, merci de la remarque.
Je me doutais que le printf risquait de générer des bugs d'affichage dans la console (genre si ça arrive au milieu de l'écriture d'une séquence de commande ansi).
Par contre il faudra que je remplace mes exit() par _exit().
L'interception et la tentative de fermeture propre du programme restent par contre valables.
L'exemple devient donc:
Les vrais naviguent en -42
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par Krunch (site web personnel) . Évalué à 3.
please_exit doit sans doute être de type sig_atomic_t et/ou volatile.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par flavien75 . Évalué à 1.
Pour le type sig_atomic_t, il faut pas exagérer. A part sur Pic (et 8051 ?) le type "int" fait 32 bits, donc l'écriture (ce n'est plus un read-modify-write) se fait en 1 cycle (non-interruptible par définition).
Et vu que la variable ne fait que passer de 0 à 1, il n'y a aucun risque de glitch. Ce n'est pas comme si 2 threads faisaient du read-modify-write dessus.
Les vrais naviguent en -42
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par benja . Évalué à 1. Dernière modification le 24 octobre 2015 à 17:40.
Désolé, cela n'a rien à voir avec le nombre de cycles. Le problème vient des optimisations que le compilateur peut faire. Si please_exit est optimisé pour être accèdé via un registre dans main, alors lorsque que le programme va se retrouvé préempté pour exécuter le signal, ben ce registre va se retrouver sauvegardé dans le "contexte" avec les autres registres sauvegardés au niveau du kernel et puis au retour, il sera restauré et, au final, la mauvaise valeur sera utilisée, voir réécrite, par main. Dans une main-loop telle que celle là, c'est sans doutes peu probable que cette optimisation se fasse (quoi qu'il faudrait que le compilateur puisse déterminer que toutes les fonctions appellées ne modifient pas la variable globale, ce qui est loin d'être impenssable) mais sur le fond, Krunch a raison…
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par benja . Évalué à 2. Dernière modification le 24 octobre 2015 à 17:53.
PS: ce n'est pas vrai qu'une écriture se fait en un cycle. Et puis même si c'était le cas, je crois que tu confonds avec un problème d'accès concurrentiel multi-CPU (et cela nécessite toujours un volatile_t pour empêcher le compilo d'aliaser dans un registre). Un signal n'a rien à voir et c'est une opération très coûteuse: cela correspond à un déscheduling puis rescheduling (donc en passant par le kernel), de quoi vider le pipeline du cpu :-)
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par benja . Évalué à 1. Dernière modification le 24 octobre 2015 à 17:14.
Ah je crois que tu te fourvoies sur ce coup par contre ;-) Ce qui est listé dans la page signal ne sont bien évidemment que les appels systèmes "async-signal-safe"… printf est une fonction de la bibliothèque C, qui (aux dernières nouvelles) appelle le syscall write() qui lui est même est "safe".
Pour répondre à flavien75, le problème n'est pas tellement que les sorties seraient entre-mellées au milieu de séquence d'échapemment (le terminal y survivra, éventuellement faire une restauration de l'état à la sortie du programme), mais bien que le comportement d'un syscall non async-signa-safe est indéfini car, à cause de la nature préemptive du signal, il pourrait être en cours d'éxécution deux fois. Comme dit juste avant, ce n'est pas un problème pour printf.
Fin bref pour en revenir à des considérations plus générales, c'est à cause de toutes ces subtilités que l'on recommande de faire un handler générique qui va retransmettre le signal dans la boucle d'évènement du programme (le fammeux "select()"). Pour l'ensemble complet des "recommandations" (c.à.d. ce qui fait la différence entre un programme buggé et un programme correcte), je ne peux que vivement conseiller la lecture/compréhension de toutes les pages man associées ou d'un bouquin de programmation système unix :-P
[^] # Re: exploiter le Ctrl+C plutôt que de le masquer ?
Posté par flavien75 . Évalué à 2.
Il va effectivement falloir que je plonge dans ces histoires d'async-signal-safe. Ce sera effectivement intéressant de voir si 2 écritures "simultanées" (programme et signal) peuvent se retrouvées entremêlées ou pas.
Enfin là pour le coup le but était juste de "neutraliser" les Ctrl+C et cette solution (la seconde) fonctionne à tous les coups et sans risque.
Dans la première le but du exit() était d'épargner à l'utilisateur d'aller faire un kill -9 quand l'application ne répond vraiment plus du tout. Elle n'était déclenchée que dans les versions beta, les versions finales quittant en général en moins d'une seconde (donc avant que l'utilisateur ne perde patience).
La remarque de Krunch m'a par contre fait réfléchir à l'effet d'un exit() au moment où la boucle principale exécuterait la fonction atexit(). J'ai effectivement des doutes sur la fiabilité du programme dans ce cas. D'où l'idée de remplacer exit() par _exit().
Les vrais naviguent en -42
# Cool
Posté par n0wic . Évalué à 1.
merci pour toutes ces réponses, j'ai un peu du mal à implémenter une solution mon code est un peu byzar en tous cas vos explication m'ont beaucoup aidé à comprendre comment on pouvait résoudre.
Je pense qu'il va falloir que je révise deux trois trucs effectivement mais en tous cas ca me sera utile!
# On avance
Posté par n0wic . Évalué à -5.
Bon j'ai un peu du mal à adapter tous ces éléments de réponse néanmoins le problème est temporairement résolu par :
printf("Ne faites surtout pas control + C, c'est pas cool.)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.