verrou pour exécution exclusive du plus récent

Le
David LE BOURGEOIS
Bonjour à tous.

J'utilise osd_cat pour afficher le résultat d'événements
concurrents, à un même endroit de l'écran.

L'affichage des informations est persistent pendant un certain
temps. Mais le délai entre deux événements peut être plus court. Et
donc, les deux inscriptions se superposent à l'écran.

Un kill sur le processus précédent en cours d'exécution permet
d'interrompre l'affichage, avant d'en lancer un nouveau. Ainsi ai-je
l'idée d'utiliser un fichier verrou, contenant le pid du processus
précédent et permettant au nouveau de le tuer avant affichage.

Voici donc le script shell, dans lequel le résultat des
événements est représenté par la date courante :

8<-
#!/bin/sh

NAME="$(basename "$0")"
LOCK="/tmp/$NAME.pid"
OSD_OPTS="-d 5"

if [ -f "$LOCK" ]
then
kill "$(cat "$LOCK")"
fi
date | osd_cat $OSD_OPTS & PID=$!
echo "$PID" > "$LOCK"
wait "$PID"
8<-

Plusieurs exécutions simultanées du script provoquent le
comportement voulu, et seule la dernière monopolise l'affichage.

Reste donc la gestion de la suppression du fichier verrou. Mais
l'ajout d'un « rm "$PID" » à la fin du script fait capoter le mécanisme.

Je m'en sors en remplaçant la dernière ligne par un celle-ci :
« wait "$PID" && rm "$LOCK" ». Mais si le dernier osd_cat renvoie un
code retour d'erreur, pour une raison quelconque, le fichier verrou
n'est pas supprimé.

Avez-vous des suggestions ?

Merci d'avance.

--
David LE BOURGEOIS
E-mail : david.lebourgeois (at) free.fr
Jabber : david.lebourgeois (at) jabber.fr
PGP : http://david.lebourgeois.free.fr/pgp/
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
David LE BOURGEOIS
Le #760242
Reste donc la gestion de la suppression du fichier verrou. Mais
l'ajout d'un « rm "$PID" » à la fin du script fait capoter le mécanisme.


Il fallait lire « rm "$LOCK" ».

--
David LE BOURGEOIS
E-mail : david.lebourgeois (at) free.fr
Jabber : david.lebourgeois (at) jabber.fr
PGP : http://david.lebourgeois.free.fr/pgp/

Nicolas George
Le #760241
David LE BOURGEOIS wrote in message
Un kill sur le processus précédent en cours d'exécution permet
d'interrompre l'affichage, avant d'en lancer un nouveau. Ainsi ai-je
l'idée d'utiliser un fichier verrou, contenant le pid du processus
précédent et permettant au nouveau de le tuer avant affichage.


Les PID notés dans un fichier, ce n'est jamais une bonne idée.

Je proposerais deux méthodes :

Si les affichages sont fréquents, garder un osd_cat en permanence, avec son
entrée sur un FIFO (et sa sortie aussi, pour garder un processus en
écriture), et écrire dans ce FIFO quand on veut. osd_cat efface
automatiquement les vieilles entres. Inconvénient : en cas d'inactivité, la
dernière entrée reste, à moins de l'effacer explicitement.

Si les affichages sont rares, utiliser la méthode décrite ci-dessus, mais
avec un lock fcntl plutôt qu'un bête fichier : fcntl permet alors de savoir
fiablemen le PID du processus qui tient l'éventuel lock. Le mieux est de
faire ça en C : tuer le processus qui a le lock, acquérir le lock, exécuter
osd_cat en gardant le file descriptor ouvert. C'est assez facile à
programmer. Quand osd_cat se termine après son timeout, le lock est libéré
automatiquement.

Luc.Habert.00__arjf
Le #760240
David LE BOURGEOIS :

LOCK="/tmp/$NAME.pid"


Là, n'importe qui peut créer un symlink avec le bon nom vers un fichier à
toi, que ton script va écraser. Ou alors, plus subtil, mettre un fichier à
lui, dans lequel il mettra le pid d'un process à toi que tu ne veux surtout
pas tuer. Tu devrais faire ça dans un répertoire à toi.

if [ -f "$LOCK" ]
then
kill "$(cat "$LOCK")"
fi
date | osd_cat $OSD_OPTS & PID=$!
echo "$PID" > "$LOCK"
wait "$PID"


Ça sent la race-condition à des kilomètres, mais ce n'est peut-être pas très
grave pour ton cas particulier.

Ah, et aussi :

date | osd_cat $OSD_OPTS & PID=$!
echo "$PID" > "$LOCK"


tu as de la chance si ça fait ce que tu veux avec ton sh. Souvent, les deux
membres du pipe sont exécutés dans des sous-shells, si bien que la suite du
script ne voit pas les affectations que l'on a faites dedans.

Plutôt que de t'embêter avec des fichiers de pid, je te conseille d'utiliser
supervise (http://cr.yp.to/daemontools/supervise.html) pour lancer et tuer
l'osd_cat.

Si tu veux éviter les race-conditions (en l'état, avec deux évènements
quasi-simultanés, il se peut que ce soit le premier qui reste affiché), il
faut ajouter un mécanisme de file d'attente, géré par un serveur qui est le
seul à lancer et tuer des osd_cat. Ça peut se faire assez facilement avec un
pipe nommé si les messages sont courts et dans un format facile à
reconnaitre (genre, un nombre précisé de lignes).

David LE BOURGEOIS
Le #760239
David LE BOURGEOIS :

LOCK="/tmp/$NAME.pid"


Là, n'importe qui peut créer un symlink avec le bon nom vers un fichier à
toi, que ton script va écraser. Ou alors, plus subtil, mettre un fichier à
lui, dans lequel il mettra le pid d'un process à toi que tu ne veux surtout
pas tuer. Tu devrais faire ça dans un répertoire à toi.


Oui, effectivement. Donc :

LOCK="~/tmp/$NAME.pid"

if [ -f "$LOCK" ]
then
kill "$(cat "$LOCK")"
fi
date | osd_cat $OSD_OPTS & PID=$!
echo "$PID" > "$LOCK"
wait "$PID"


Ça sent la race-condition à des kilomètres, mais ce n'est peut-être pas très
grave pour ton cas particulier.

Ah, et aussi :

date | osd_cat $OSD_OPTS & PID=$!
echo "$PID" > "$LOCK"


tu as de la chance si ça fait ce que tu veux avec ton sh. Souvent, les deux
membres du pipe sont exécutés dans des sous-shells, si bien que la suite du
script ne voit pas les affectations que l'on a faites dedans.


Comment protéger alors l'affectation ? Avec les accolades ?

$ { date | osd_cat ; } & PID=$!


Mais, le date n'étant là que pour le test, la ligne deviendra au final
« osd_cat $OSD_OPTS & PID=$! ».

Plutôt que de t'embêter avec des fichiers de pid, je te conseille d'utiliser
supervise (http://cr.yp.to/daemontools/supervise.html) pour lancer et tuer
l'osd_cat.


Je l'ajoute de suite à ma panoplie.

Si tu veux éviter les race-conditions (en l'état, avec deux évènements
quasi-simultanés, il se peut que ce soit le premier qui reste affiché), il
faut ajouter un mécanisme de file d'attente, géré par un serveur qui est le
seul à lancer et tuer des osd_cat. Ça peut se faire assez facilement avec un
pipe nommé si les messages sont courts et dans un format facile à
reconnaitre (genre, un nombre précisé de lignes).


Je découvre à l'instant le couple osdsh et osdctl qui correspond un peu
à cette idée.


Merci pour ces conseils.

--
David LE BOURGEOIS
E-mail : david.lebourgeois (at) free.fr
Jabber : david.lebourgeois (at) jabber.fr
PGP : http://david.lebourgeois.free.fr/pgp/


Luc.Habert.00__arjf
Le #760238
David LE BOURGEOIS :

Oui, effectivement. Donc :

LOCK="~/tmp/$NAME.pid"


Il faut enlever les « " », sinon le shell n'expanse pas le « ~ ».

Comment protéger alors l'affectation ? Avec les accolades ?

$ { date | osd_cat ; } & PID=$!


Le osd_cat a toutes les chances d'être lancé dans un process différent, si
bien que le « $! » ne pointera pas sur le bon process. Je ne crois pas qu'il
y ait d'autre solution en shell que d'echoer le pid dans un pipe et de le
relire depuis le shell père (le problème est qu'on ne controle pas assez
bien dans quel sens il fait ses forks). Quelque chose comme :

exec 9>&1
PID=$(date | { osd_cat >&9 9>&- & echo $!; })
exec 9>&-

(les redirections avec le fd 9, c'est pour sauvegarder le stdout d'origine
et le redonner à osd_cat).


Mais, le date n'étant là que pour le test, la ligne deviendra au final
« osd_cat $OSD_OPTS & PID=$! ».


oki

David LE BOURGEOIS
Le #759947
David LE BOURGEOIS wrote in message
Un kill sur le processus précédent en cours d'exécution permet
d'interrompre l'affichage, avant d'en lancer un nouveau. Ainsi ai-je
l'idée d'utiliser un fichier verrou, contenant le pid du processus
précédent et permettant au nouveau de le tuer avant affichage.


Les PID notés dans un fichier, ce n'est jamais une bonne idée.


C'est ce que je vois.

Je proposerais deux méthodes :

Si les affichages sont fréquents, garder un osd_cat en permanence, avec son
entrée sur un FIFO (et sa sortie aussi, pour garder un processus en
écriture), et écrire dans ce FIFO quand on veut. osd_cat efface
automatiquement les vieilles entres. Inconvénient : en cas d'inactivité, la
dernière entrée reste, à moins de l'effacer explicitement.


J'essaie avec le FIFO :

$ mkfifo foo
$ tail -f foo | osd_cat -d 5 -l 2 -a

Et d'un autre côté je provoque les événements :

$ for i in a b c d ; do echo "$i" > foo ; sleep 2 ; done

Mais osd_cat fait du scrolling sur ses 2 lignes.
Donc pour simuler le remplacement de l'affichage précédent, il faut que
je fournisse en entrée le même nom de lignes que passées en paramètre.

Si les affichages sont rares, utiliser la méthode décrite ci-dessus, mais
avec un lock fcntl plutôt qu'un bête fichier : fcntl permet alors de savoir
fiablemen le PID du processus qui tient l'éventuel lock. Le mieux est de
faire ça en C : tuer le processus qui a le lock, acquérir le lock, exécuter
osd_cat en gardant le file descriptor ouvert. C'est assez facile à
programmer. Quand osd_cat se termine après son timeout, le lock est libéré
automatiquement.


Quitte à le faire en C, je vais plutôt m'orienter vers la libxosd qui
fournit xosd_hide() et xosd_destroy().
D'ailleurs, en regardant les sources, il existe le plugin xmms-osd qui
utilise ces deux appels, et fait exactement comme je veux.
Reste donc à m'en inspirer.


Merci pour ces réponses.

--
David LE BOURGEOIS
E-mail : david.lebourgeois (at) free.fr
Jabber : david.lebourgeois (at) jabber.fr
PGP : http://david.lebourgeois.free.fr/pgp/


Nicolas George
Le #759946
David LE BOURGEOIS wrote in message
J'essaie avec le FIFO :

$ mkfifo foo
$ tail -f foo | osd_cat -d 5 -l 2 -a


On n'utilise pas tail -f avec un fifo, on se contente de lire dessus. Donc :

osd_cat ... < foo

Mais ça, ça va faire se terminer osd_cat après la première écriture, ce
qu'on ne veut pas. Il faut un processus qui garde le FIFO ouvert en
écriture, mais sans rien écrire, pendant toute la durée de vie d'osd_cat.
Comme osd_cat lui-même n'écrit rien, c'est un bon candidat. Donc :

osd_cat ... <> foo

Quitte à le faire en C, je vais plutôt m'orienter vers la libxosd qui
fournit xosd_hide() et xosd_destroy().
D'ailleurs, en regardant les sources, il existe le plugin xmms-osd qui
utilise ces deux appels, et fait exactement comme je veux.
Reste donc à m'en inspirer.


C'est quand même un ordre de grandeur plus compliqué : faire un fcntl, un
kill, un deuxième fcntl et un exec, ça se code en cinquante lignes, messages
d'aide compris.

David LE BOURGEOIS
Le #759945
David LE BOURGEOIS wrote in message
J'essaie avec le FIFO :

$ mkfifo foo
$ tail -f foo | osd_cat -d 5 -l 2 -a


On n'utilise pas tail -f avec un fifo, on se contente de lire dessus. Donc :

osd_cat ... < foo

Mais ça, ça va faire se terminer osd_cat après la première écriture, ce
qu'on ne veut pas. Il faut un processus qui garde le FIFO ouvert en
écriture, mais sans rien écrire, pendant toute la durée de vie d'osd_cat.
Comme osd_cat lui-même n'écrit rien, c'est un bon candidat. Donc :

osd_cat ... <> foo


D'un côté je lance :

$ mkfifo fifo
$ osd_cat -l 2 -d 5 -a <> foo

De l'autre :

$ echo a > fifo ; echo b > fifo

Mais là, le b s'affiche en dessous du a.

--
David LE BOURGEOIS
E-mail : david.lebourgeois (at) free.fr
Jabber : david.lebourgeois (at) jabber.fr
PGP : http://david.lebourgeois.free.fr/pgp/


Nicolas George
Le #759944
David LE BOURGEOIS wrote in message
$ osd_cat -l 2 -d 5 -a <> foo

Mais là, le b s'affiche en dessous du a.


Ben c'est normal, tu as mis -l 2. Essaie avec -l 1.

David LE BOURGEOIS
Le #759943
David LE BOURGEOIS wrote in message
$ osd_cat -l 2 -d 5 -a <> foo

Mais là, le b s'affiche en dessous du a.


Ben c'est normal, tu as mis -l 2. Essaie avec -l 1.


C'est vrai que les messages d'événements que j'ai pris jusqu'à
maintenant sont date et echo, et ne produisent qu'une seule ligne.
Mais actuellement j'ai besoin de 2 lignes d'affichage, voire peut-être
3 dans le futur.

Sinon, oui ça fonctionne effectivement pour une seule ligne.

--
David LE BOURGEOIS
E-mail : david.lebourgeois (at) free.fr
Jabber : david.lebourgeois (at) jabber.fr
PGP : http://david.lebourgeois.free.fr/pgp/


Publicité
Poster une réponse
Anonyme