Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Ai-je resolu ce probleme "vieux comme le shell" ?

10 réponses
Avatar
Daniel Déchelotte
Bonjour,

"Pardonnez ma question candide" aurait aussi pu etre mon sujet, mais
c'etait pris ;-)

Donc j'aimerais qu'un script shell s'endorme, et qu'on puisse le
reveiller pour effectuer une tache, puis qu'il se rendorme.

J'ai ce squelette :

### Le serveur
#! /bin/bash
# Il met son PID a un endroit bien connu
function nicequit() {
/bin/rm "$pid_fn"
exit 0
}

trap nicequit TERM

echo $$ > "$pid_fn"

while true; do
# Monitor mode. Pour que suspend fonctionne.
set -m

#
# Il fait ce qu'il a a faire
#

# Puis il s'endort
suspend
done


### Le client

#
# Il prepare le travail
#

# Puis il reveille le serveur
kill -CONT $(cat "$pid_fn")


Ca a un comportement un peu bizarre (quand on tue le serveur, il emporte
avec lui le terminal), mais ca a l'air de fonctionner.

Est-ce que cette methode présente des problemes que je n'aurais pas
encore décelés ? Y a-t-il une facon plus standard, plus fiable ou plus
propre pour arriver à la meme fonctionnalité ?

--
Daniel Déchelotte
http://yo.dan.free.fr/

10 réponses

Avatar
Thierry Boudet
On 2006-02-21, Daniel Déchelotte wrote:

Donc j'aimerais qu'un script shell s'endorme, et qu'on puisse le
reveiller pour effectuer une tache, puis qu'il se rendorme.

Dans le temps, j'ai eu le même genre de problème. Si je me souviens

bien, j'avais résolu l'arrèt d'un script shell par un petit proggy
en C qui attendait sur un pipe nommé, ou un fifo. Pour débloquer,
il suffisait d'un "echo -n 'G' > /tmp/eul_fifo" dans un autre script.

man mkfifo, et voir ce qu'on peut en faire dans un shell-script...



--
Unix, c'est comme la science: Plus on le connaît, plus on en trouve à
apprendre. C'est une assez bonne école de l'humilité, et on a plutôt
tendance à être dominé par ce qu'on ignore qu'à pavaner du peu qu'on sait.
-<>- Tinou, ou la sagesse made in f.m.b.l -<>-

Avatar
Stephane Chazelas
On Tue, 21 Feb 2006 13:51:38 +0100, Daniel Déchelotte wrote:
Bonjour,

"Pardonnez ma question candide" aurait aussi pu etre mon sujet, mais
c'etait pris ;-)

Donc j'aimerais qu'un script shell s'endorme, et qu'on puisse le
reveiller pour effectuer une tache, puis qu'il se rendorme.

J'ai ce squelette :

### Le serveur
#! /bin/bash
# Il met son PID a un endroit bien connu
function nicequit() {


La syntax pour bash et tous les Bourne-like shells est:

nicequit() {

bash ignore le "function" ce qui fait que ca marche, mais cette
syntaxe n'est pas standard.

/bin/rm "$pid_fn"
exit 0
}

trap nicequit TERM

echo $$ > "$pid_fn"

while true; do
# Monitor mode. Pour que suspend fonctionne.
set -m


Dans un script le job control ne fait pas beaucoup de sens. Ca
va faire des trucs nasty avec les process group et le terminal.
Tu auras de problemes avec les CTRL-C, CTRL-Z...

#
# Il fait ce qu'il a a faire
#

# Puis il s'endort
suspend


suspend

envoir un SIGSTOP a tout le process group. Donc ca peut
suspendre plus que ce que tu peux t'attendre. Par exemple le
parent s'il n'est pas un shell interactif (n'a pas mis ton
script dans un nouveau process group).

Utilise plutot:

kill -STOP "$$"

et enleve le "set -m"

--
Stephane

Avatar
Vincent Lefevre
Dans l'article ,
Stephane Chazelas écrit:

suspend

envoir un SIGSTOP a tout le process group. Donc ca peut
suspendre plus que ce que tu peux t'attendre. Par exemple le
parent s'il n'est pas un shell interactif (n'a pas mis ton
script dans un nouveau process group).


Et ce n'est pas POSIX.

Utilise plutot:

kill -STOP "$$"


Est-il garanti que le signal sera reçu immédiatement, i.e. que la
commande suivante ne sera exécutée qu'après le SIGCONT?

Au passage, ça résout le problème que je me posais il y a quelques
jours (cf "attente d'un signal en shell POSIX"), je suppose.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Stephane Chazelas
2006-02-21, 19:08(+00), Vincent Lefevre:
Dans l'article ,
Stephane Chazelas écrit:

suspend

envoir un SIGSTOP a tout le process group. Donc ca peut
suspendre plus que ce que tu peux t'attendre. Par exemple le
parent s'il n'est pas un shell interactif (n'a pas mis ton
script dans un nouveau process group).


Et ce n'est pas POSIX.

Utilise plutot:

kill -STOP "$$"


Est-il garanti que le signal sera reçu immédiatement, i.e. que la
commande suivante ne sera exécutée qu'après le SIGCONT?


Normalement oui, d'apres POSIX et c'est ce que fait "suspend" en
tout cas.

SUSv3> If the value of pid causes sig to be generated for the
SUSv3> sending process, and if sig is not blocked for the
SUSv3> calling thread and if no other thread has sig unblocked
SUSv3> or is waiting in a sigwait() function for sig, either sig
SUSv3> or at least one pending unblocked signal shall be
SUSv3> delivered to the sending thread before kill() returns.

Au passage, ça résout le problème que je me posais il y a quelques
jours (cf "attente d'un signal en shell POSIX"), je suppose.




--
Stéphane


Avatar
Nicolas George
Stephane Chazelas wrote in message
:
Normalement oui, d'apres POSIX et c'est ce que fait "suspend" en
tout cas.

SUSv3> If the value of pid causes sig to be generated for the
SUSv3> sending process, and if sig is not blocked for the
SUSv3> calling thread and if no other thread has sig unblocked
SUSv3> or is waiting in a sigwait() function for sig, either sig
SUSv3> or at least one pending unblocked signal shall be
SUSv3> delivered to the sending thread before kill() returns.


Ça, c'est vrai pour un programme en C. Pour que ça s'applique au shell, il
faut que kill soit un builtin, ce qui n'est pas garanti.

Avatar
Daniel Déchelotte

Stephane Chazelas écrit:

suspend

envoir un SIGSTOP a tout le process group. Donc ca peut
suspendre plus que ce que tu peux t'attendre. Par exemple le
parent s'il n'est pas un shell interactif (n'a pas mis ton
script dans un nouveau process group).


Et ce n'est pas POSIX.

Utilise plutot:

kill -STOP "$$"



Merci de vos réponses.
Je confirme, ca marche mieux (en plus d'etre plus standard) : le
terminal résiste au kill du « serveur ».

Un truc bizarre : « kill lepid » ne tue pas immédiatement le serveur. Il
faut ensuite lui envoyer « kill -CONT lepid » pour qu'il prenne en
compte le TERM.

Au passage, ça résout le problème que je me posais il y a quelques
jours (cf "attente d'un signal en shell POSIX"), je suppose.


C'est ton article qui m'a fait me replonger dans cette histoire ! :)
J'avais un truc pas vraiment satisfaisant, avec un « sleep 30 » en
boucle. (mais un shell qui a lancé un sleep ne peut pas être réveillé
par un signal, cas d'école paraît-il) Bon, la, si on oublie de killer le
serveur, rien ne se passe. Ca a ses avantages et ses inconvenients.

--
Daniel Déchelotte
http://yo.dan.free.fr/


Avatar
lhabert
Daniel Déchelotte :

Un truc bizarre : « kill lepid » ne tue pas immédiatement le serveur. Il
faut ensuite lui envoyer « kill -CONT lepid » pour qu'il prenne en
compte le TERM.


C'est normal. Il faut faire un kill -KILL pour causer une fin brutale. Les
autres signaux, vu qu'il peuvent être rattrapés, l'OS attend que le process
soit relancé pour les livrer (bon, d'accord, pour les cas où il y a un
SIG_DFL d'installé, l'OS pourrait le traiter directement sans attendre que
le process soit relancé, je ne sais pas du tout si il y a quoi que ce soit
de spécifié à ce sujet dans les normes).

(mais un shell qui a lancé un sleep ne peut pas être réveillé par un
signal, cas d'école paraît-il)


Bah il suffit de tuer le sleep. Enfin, si jamais sleep se trouve être
builtin, je ne sais pas du tout ce qu'il se passe, mais ça n'a pas l'air
très courant (que ce soit bash, zsh, dash, les sh de (free|open)bsd et
solaris, aucun n'a l'air de le faire).

Avatar
Vincent Lefevre
Dans l'article <dtg831$2lde$,
Luc Habert écrit:

Daniel Déchelotte :

(mais un shell qui a lancé un sleep ne peut pas être réveillé par un
signal, cas d'école paraît-il)


Bah il suffit de tuer le sleep.


Faut pouvoir connaître le pid du sleep, et cela me semble difficilement
faisable proprement.

Enfin, si jamais sleep se trouve être builtin, je ne sais pas du
tout ce qu'il se passe, mais ça n'a pas l'air très courant (que ce
soit bash, zsh, dash, les sh de (free|open)bsd et solaris, aucun n'a
l'air de le faire).


Mais ksh93 a un builtin sleep (pas pdksh, ni mksh cependant). On ne
peut alors qu'envoyer un signal au shell, et c'est le comportement
POSIX qui s'applique: le signal est pris en compte à la fin du sleep.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Stephane Chazelas
2006-02-21, 21:39(+00), Nicolas George:
Stephane Chazelas wrote in message
:
Normalement oui, d'apres POSIX et c'est ce que fait "suspend" en
tout cas.

SUSv3> If the value of pid causes sig to be generated for the
SUSv3> sending process, and if sig is not blocked for the
SUSv3> calling thread and if no other thread has sig unblocked
SUSv3> or is waiting in a sigwait() function for sig, either sig
SUSv3> or at least one pending unblocked signal shall be
SUSv3> delivered to the sending thread before kill() returns.


Ça, c'est vrai pour un programme en C. Pour que ça s'applique au shell, il
faut que kill soit un builtin, ce qui n'est pas garanti.


Exact. Cela dit, si le shell reprend le control apres que kill
ait fini, ca veut dire qu'il a recu le SIGCHLD et le SIGCHLD est
envoyé apres le SIGSTOP, donc j'aurais tendance a croire que le
SIGSTOP est delivré avant que le shell ait fini d'attendre la
fin de la commande kill.

--
Stéphane


Avatar
Vincent Lefevre
Dans l'article ,
Stephane Chazelas écrit:

2006-02-21, 21:39(+00), Nicolas George:
Ça, c'est vrai pour un programme en C. Pour que ça s'applique au
shell, il faut que kill soit un builtin, ce qui n'est pas garanti.


Exact. Cela dit, si le shell reprend le control apres que kill
ait fini, ca veut dire qu'il a recu le SIGCHLD et le SIGCHLD est
envoyé apres le SIGSTOP, donc j'aurais tendance a croire que le
SIGSTOP est delivré avant que le shell ait fini d'attendre la
fin de la commande kill.


Oui, mais qui dit que les signaux sont reçus dans l'ordre?
Une implémentation pourrait très bien mettre des priorités
sur les signaux, non? (Je n'ai pas vérifié dans la norme...)
Traiter les SIGCHLD de manière prioritaire permettrait de
libérer la table des processus au plus vite, par exemple...

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA