OVH Cloud OVH Cloud

gerer un signal usr1

9 réponses
Avatar
gilles civario
Bonjour.
Je souhaiterais installer un gestionnaire de signal spécifique.
Concrètement, j'aimerais qu'avec un kill -USR1 <pid>, un message
s'affiche, et que le process <pid> continue sa route comme si
rien ne s'était produit.
Est-ce possible simplement, et de manière la plus portable possible ?
Si oui, comment faire pour qu'un code déjà existant puisse répondre
au signal de cette manière, sans recompilation ni modification des
sources (mais éventuellement via une édition de liens) ?
Merci.

Gilles.

9 réponses

Avatar
gilles civario
gilles civario wrote:

Bonjour.
Je souhaiterais installer un gestionnaire de signal spécifique.
Concrètement, j'aimerais qu'avec un kill -USR1 <pid>, un message
s'affiche, et que le process <pid> continue sa route comme si
rien ne s'était produit.
Est-ce possible simplement, et de manière la plus portable possible ?
Si oui, comment faire pour qu'un code déjà existant puisse répondre
au signal de cette manière, sans recompilation ni modification des
sources (mais éventuellement via une édition de liens) ?
Merci.


Bonjour.
Voici ce que j'ai réussit à pondre, répondant en gros à mes besoins :
(lorsque j'ai posé ma question j'avais déjà tout, sauf le nouvel appel
à la fonction signaldans le handler lui-même)

$ cat set_signal.c
#include <stdio.h>
#include <signal.h>

void sig_act(int val) {
fprintf(stderr,"coucoun");
signal(SIGUSR1,sig_act);
}

void set_signal_USR1(void) {
signal(SIGUSR1,sig_act);
}
$ cat main.c
#include <stdio.h>
#include <unistd.h>

int
main(int ac, char** av) {
int i;
printf("dans le mainn");
for (i=1; i! ; ++i)
sleep(i);
printf("fini!n");
return 0;
}
$ cc -c set_signal.c
$ ar cru libsig.a set_signal.o
$ cc -c main.c
$ cc -o test_sig main.o -Wl,-init,set_signal_USR1 -L. -lsig
$ ./test_sig&
[1] 731664
$ dans le main

$ kill -USR1 731664
coucou
$ kill -USR1 731664
coucou
$ kill -USR1 731664
coucou
$ kill -USR1 731664
coucou
$ kill -USR1 731664
coucou
fini!
$
[1]+ Done ./test_sig

J'ai également une version avec sigaction plutôt que signal.
Le quel des deux est le mieux pour mon propos ?
L'exemple ci-dessus marche sur HP alpha avec les compilateurs
Compaq et gcc 3.2.3. Mais sous Linux itanium avec gcc 2.96, le
signal n'est pas positionné, bien que la ligne de commande
d'étion de liens passe.
Qu'en penssez vous.
Et si, comme c'est le cas sur une troisième machine dont je
dispose, l'éditeur de liens ne dispose pas du hook pour ajouter
une fonction à l'initialisation, y a il une solution autre que
cell présentée ici :

http://groups.google.fr/groups?hl=fr&lr=&ie=UTF-8&oe=UTF-8&selm‡d6n38g5c.fsf%40thalassa.informatimago.com

(sachant que je n'ai pas non plus de désassembleur sur cette
machine)

Avatar
Pascal Bourguignon
gilles civario writes:

gilles civario wrote:

Bonjour.
Je souhaiterais installer un gestionnaire de signal spécifique.
Concrètement, j'aimerais qu'avec un kill -USR1 <pid>, un message
s'affiche, et que le process <pid> continue sa route comme si
rien ne s'était produit.
Est-ce possible simplement, et de manière la plus portable possible ?
Si oui, comment faire pour qu'un code déjà existant puisse répondre
au signal de cette manière, sans recompilation ni modification des
sources (mais éventuellement via une édition de liens) ?
Merci.


Bonjour.
Voici ce que j'ai réussit à pondre, répondant en gros à mes besoins :
(lorsque j'ai posé ma question j'avais déjà tout, sauf le nouvel appel
à la fonction signaldans le handler lui-même)

void sig_act(int val) {
fprintf(stderr,"coucoun");
signal(SIGUSR1,sig_act);
}


Ce n'est pas une bonne idée!

Le programme pourrait être en train de fprintf(stderr,un_tres_long_message);
et alors le coucou se mélangerait au millieu d'un_tres_long_message.

Le mieux est de se contenter dans les handlers de positionner un flag
qui sera lu dans la boucle principale du programme.

static int recu_sig_usr1=0;
void sig_act(int val) {
recu_sig_usr1=1;
signal(SIGUSR1,sig_act);
}

int main(int ac, char** av) {
set_signal_USR1(); /* les initialisation viennent ici! */
printf("dans le mainn");
{
int i;
for (i=1; i!=(20*19)/2; ++i){
if(recu_sig_usr1){
recu_sig_usr1=0;
fprintf(stderr,"coucoun");
}
sleep(1); /* ou fprintf(stderr,un_tres_grand_message); */
}
}
printf("fini!n");
return 0;
}



En général on écrit main comme ça:

int status=0;

int main(int ac, char** av) {
intialisations();
travail();
terminaisons();
return(status);
}


--
__Pascal_Bourguignon__ . * * . * .* .
http://www.informatimago.com/ . * . .*
* . . / () . *
Living free in Alaska or in Siberia, a . . / . . * .
grizzli's life expectancy is 35 years, .*. / * . .
but no more than 8 years in captivity. . /* o .
http://www.theadvocates.org/ * '''||''' .
SCO Spam-magnet: ******************


Avatar
gilles civario
Pascal Bourguignon wrote:

gilles civario writes:


gilles civario wrote:


Bonjour.
Je souhaiterais installer un gestionnaire de signal spécifique.
Concrètement, j'aimerais qu'avec un kill -USR1 <pid>, un message
s'affiche, et que le process <pid> continue sa route comme si
rien ne s'était produit.
Est-ce possible simplement, et de manière la plus portable possible ?
Si oui, comment faire pour qu'un code déjà existant puisse répondre
au signal de cette manière, sans recompilation ni modification des
sources (mais éventuellement via une édition de liens) ?
Merci.


Bonjour.
Voici ce que j'ai réussit à pondre, répondant en gros à mes besoins :
(lorsque j'ai posé ma question j'avais déjà tout, sauf le nouvel appel
à la fonction signaldans le handler lui-même)

void sig_act(int val) {
fprintf(stderr,"coucoun");
signal(SIGUSR1,sig_act);
}



Ce n'est pas une bonne idée!

Le programme pourrait être en train de fprintf(stderr,un_tres_long_message);
et alors le coucou se mélangerait au millieu d'un_tres_long_message.


Et m***, je n'avais pas pensé à ça.

Le mieux est de se contenter dans les handlers de positionner un flag
qui sera lu dans la boucle principale du programme.

static int recu_sig_usr1=0;
void sig_act(int val) {
recu_sig_usr1=1;
signal(SIGUSR1,sig_act);
}

int main(int ac, char** av) {
set_signal_USR1(); /* les initialisation viennent ici! */
printf("dans le mainn");
{
int i;
for (i=1; i!=(20*19)/2; ++i){
^^^^^^^^

J'ai beaucoup aimé ça, ça m'a bien fait rire
if(recu_sig_usr1){
recu_sig_usr1=0;
fprintf(stderr,"coucoun");
}
sleep(1); /* ou fprintf(stderr,un_tres_grand_message); */
}
}
printf("fini!n");
return 0;
}


Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?
Au final, ce que je souhaite réaliser, c'est une petite commande
lisant les compteurs hardware de la machine, pour afficher au run-time
des information sur un processus en cour. Or l'appel à la routine
de lecture des compteurs hardware ne peut se faire que par le processus
lui-même. D'où l'idée de passer par un signal handler.
Quelqu'un a une meilleure idée (je suis preneur de toute suggestion).

Gilles.


En général on écrit main comme ça:

int status=0;

int main(int ac, char** av) {
intialisations();
travail();
terminaisons();
return(status);
}


Ce n'est pas moi qui écrit le main...



Avatar
Jean-Marc Bourguet
gilles civario writes:

Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?


Il n'y a pas de notion d'ecran sous Unix et je vois au moins 3
possibilites: stdout et le terminal controllant le processus
(/dev/tty) et la console du systeme (/dev/console). De toute maniere,
j'ai du mal a voir comment tu vas eviter les interferences possibles.

Si j'ai bonne memoire, POSIX autorise l'utilisation de write dans un
signal (c'est au moins le cas pour solaris, le man indique
Async-Signal-Safe).

--
Jean-Marc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
gilles civario
Jean-Marc Bourguet wrote:

gilles civario writes:


Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?



Il n'y a pas de notion d'ecran sous Unix et je vois au moins 3
possibilites: stdout et le terminal controllant le processus
(/dev/tty) et la console du systeme (/dev/console). De toute maniere,
j'ai du mal a voir comment tu vas eviter les interferences possibles.

Si j'ai bonne memoire, POSIX autorise l'utilisation de write dans un
signal (c'est au moins le cas pour solaris, le man indique
Async-Signal-Safe).

En fait, les processus que je souhaite interroger grace au signal seront

lancés en batch. Donc leurs sortie standard en erreur sera déjà connectée
à un fichier. Je ne peux donc pas écrire dessus car je vais la polluer.
J'avais en tête un truc du style fifo, créé dans le handler, et sur lequel
le processus faisant le kill -USR1 lirait. Sauf que je n'y connais rien
en matière de pipe nommé, socket and co... Y a-t-il de l'espoire de ce coté là ?


Avatar
Jean-Marc Bourguet
gilles civario writes:

Jean-Marc Bourguet wrote:

gilles civario writes:

Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?
Il n'y a pas de notion d'ecran sous Unix et je vois au moins 3

possibilites: stdout et le terminal controllant le processus
(/dev/tty) et la console du systeme (/dev/console). De toute maniere,
j'ai du mal a voir comment tu vas eviter les interferences possibles.
Si j'ai bonne memoire, POSIX autorise l'utilisation de write dans un
signal (c'est au moins le cas pour solaris, le man indique
Async-Signal-Safe).

En fait, les processus que je souhaite interroger grace au signal

seront lancés en batch. Donc leurs sortie standard en erreur sera
déjà connectée à un fichier. Je ne peux donc pas écrire dessus car
je vais la polluer. J'avais en tête un truc du style fifo, créé
dans le handler, et sur lequel le processus faisant le kill -USR1
lirait. Sauf que je n'y connais rien en matière de pipe nommé,
socket and co... Y a-t-il de l'espoire de ce coté là ?


Je ne vois a priori pas de probleme. Il faut naturellement travailler
avec des appels systemes et verifier qu'ils sont appelables depuis un
signal.

A+

--
Jean-Marc
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
Pascal Bourguignon
gilles civario writes:

Pascal Bourguignon wrote:

gilles civario writes:

gilles civario wrote:


Bonjour.
Je souhaiterais installer un gestionnaire de signal spécifique.
Concrètement, j'aimerais qu'avec un kill -USR1 <pid>, un message
s'affiche, et que le process <pid> continue sa route comme si
rien ne s'était produit.
Est-ce possible simplement, et de manière la plus portable possible ?
Si oui, comment faire pour qu'un code déjà existant puisse répondre
au signal de cette manière, sans recompilation ni modification des
sources (mais éventuellement via une édition de liens) ?
Merci.


Bonjour.
Voici ce que j'ai réussit à pondre, répondant en gros à mes besoins :
(lorsque j'ai posé ma question j'avais déjà tout, sauf le nouvel appel
à la fonction signaldans le handler lui-même)

void sig_act(int val) {
fprintf(stderr,"coucoun");
signal(SIGUSR1,sig_act);
}
Ce n'est pas une bonne idée!

Le programme pourrait être en train de
fprintf(stderr,un_tres_long_message); et alors le coucou se
mélangerait au millieu d'un_tres_long_message.


Et m***, je n'avais pas pensé à ça.

Le mieux est de se contenter dans les handlers de positionner un flag
qui sera lu dans la boucle principale du programme.
static int recu_sig_usr1=0;
void sig_act(int val) {
recu_sig_usr1=1;
signal(SIGUSR1,sig_act);
}
int main(int ac, char** av) {
set_signal_USR1(); /* les initialisation viennent ici! */
printf("dans le mainn");
{
int i;
for (i=1; i!=(20*19)/2; ++i){
^^^^^^^^

J'ai beaucoup aimé ça, ça m'a bien fait rire


Bin oui, enfin, je me suis trompé, c'était
for(i=1;i! ;++i){sleep(i);} alors c'est à peu près équivalent à
sleep(19*18/2); ou à for(i=1;i!*18/2;++i){sleep(1);}. La
différence, c'est que dans le premier cas on n'a que 20^W (d'où
l'intérêt de commencer à compter par zéro!) 19 occasions d'être
interrompu avant la fin de la période de sommeil, alors que dans la
deuxième on n'en a qu'une seule et dans la dernière on en a 19*18/2.

C'est surement important quand on s'attend à recevoir des
interruptions (des signaux)! Il vaudrait mieux regarder sa montre et
écrire:

time_t final_time=time(0)+19*18/2;
while(time(0)<final_time){
process_received_signals();
sleep(1);
}


Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?
Au final, ce que je souhaite réaliser, c'est une petite commande
lisant les compteurs hardware de la machine, pour afficher au run-time
des information sur un processus en cour. Or l'appel à la routine
de lecture des compteurs hardware ne peut se faire que par le processus
lui-même. D'où l'idée de passer par un signal handler.
Quelqu'un a une meilleure idée (je suis preneur de toute suggestion).


Oui, il suffit d'ouvrir un fichier distinct de stdout et stderr.

Sinon, si ça devient légèrement plus compliqué, on peut envisager
d'utiliser des threads.

Mais dans les deux cas il faut faire attention au risque de
collision. Que se passerait il si le processus en question était en
train d'effectuer une "lecture des compteurs hardware" ?

--
__Pascal_Bourguignon__ . * * . * .* .
http://www.informatimago.com/ . * . .*
* . . / () . *
Living free in Alaska or in Siberia, a . . / . . * .
grizzli's life expectancy is 35 years, .*. / * . .
but no more than 8 years in captivity. . /* o .
http://www.theadvocates.org/ * '''||''' .
SCO Spam-magnet: ******************




Avatar
Pascal Bourguignon
Jean-Marc Bourguet writes:

gilles civario writes:

Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?


Il n'y a pas de notion d'ecran sous Unix et je vois au moins 3
possibilites: stdout et le terminal controllant le processus
(/dev/tty) et la console du systeme (/dev/console). De toute maniere,
j'ai du mal a voir comment tu vas eviter les interferences possibles.

Si j'ai bonne memoire, POSIX autorise l'utilisation de write dans un
signal (c'est au moins le cas pour solaris, le man indique
Async-Signal-Safe).


Oui, mais ça ne signifie pas que le traitement du signal ne puisse
interrompre un write du processus principal (probablement entre deux
blocs) avec un résultat inférieur à la taille requise. Si le
gestionaire de signal écrit à ce moment là, quand rend la mains, le
processus principal fini normalement l'écriture et on se retrouve avec
des choses  mélangées.

--
__Pascal_Bourguignon__ . * * . * .* .
http://www.informatimago.com/ . * . .*
* . . / () . *
Living free in Alaska or in Siberia, a . . / . . * .
grizzli's life expectancy is 35 years, .*. / * . .
but no more than 8 years in captivity. . /* o .
http://www.theadvocates.org/ * '''||''' .
SCO Spam-magnet: ******************


Avatar
Pascal Bourguignon
gilles civario writes:

Jean-Marc Bourguet wrote:

gilles civario writes:

Sauf que l'une de mes contraintes (forte), est de ne pas modifier le
code existant. Dans le pire des cas, je pourrais ajouter un appel
de fonction, permettant entre autre de positionner le signal-handler,
mais en aucun cas une autre modification n'est possible.
Donc, y a-t-il un moyen d'écrire sur un canal dont on en sûre qu'il ne
sera pas utilisé par ailleurs, et d'afficher la sortie à l'écran ?
Il n'y a pas de notion d'ecran sous Unix et je vois au moins 3

possibilites: stdout et le terminal controllant le processus
(/dev/tty) et la console du systeme (/dev/console). De toute maniere,
j'ai du mal a voir comment tu vas eviter les interferences possibles.
Si j'ai bonne memoire, POSIX autorise l'utilisation de write dans un
signal (c'est au moins le cas pour solaris, le man indique
Async-Signal-Safe).


En fait, les processus que je souhaite interroger grace au signal
seront lancés en batch. Donc leurs sortie standard en erreur sera
déjà connectée à un fichier. Je ne peux donc pas écrire dessus car
je vais la polluer. J'avais en tête un truc du style fifo, créé
dans le handler, et sur lequel le processus faisant le kill -USR1
lirait. Sauf que je n'y connais rien en matière de pipe nommé,
socket and co... Y a-t-il de l'espoir de ce coté là ?


Si le gestionaire de signal travaille avec ses propres fichiers ou
sockets, indépendants de ceux du processus principal, alors il ne
devrait pas y avoir de problème.

--
__Pascal_Bourguignon__ . * * . * .* .
http://www.informatimago.com/ . * . .*
* . . / () . *
Living free in Alaska or in Siberia, a . . / . . * .
grizzli's life expectancy is 35 years, .*. / * . .
but no more than 8 years in captivity. . /* o .
http://www.theadvocates.org/ * '''||''' .
SCO Spam-magnet: ******************