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

read() et signaux

4 réponses
Avatar
JKB
Bonjour à tous,

Je viens de trouver un bug sournois dans un de mes programmes écrit
en C et en lisant la page man de read() [Solaris], je m'aperçois
avec horreur que lorsque je lis dans un pipe, la fonction read()
peut être interrompue et que le read() peut s'arrêter avant d'avoir
lu le nombre de caractères demandés.

Problème : je synchronise plusieurs processus à l'aide de pipes et
de signaux. Comment s'arranger pour que les appels read() ne soient
pas interrompus par des signaux, donc que le contenu de mon buffer
soit celui attendu ?

En d'autres termes, j'aimerais qu'une ligne comme :

read(pipe, buffer, longueur)s

ne renvoie que 0, -1 ou longueur à l'exclusion de toute autre
valeur. Je sèche un peu (d'autant plus que j'utilise derrière cela
des signaux à temps réel).

Le code doit pouvoir tourner sous Solaris et au moins Linux et je ne
vois pas vraiment par où commencer...

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.

4 réponses

Avatar
Aris
En d'autres termes, j'aimerais qu'une ligne comme :

read(pipe, buffer, longueur)s

ne renvoie que 0, -1 ou longueur à l'exclusion de toute autre
valeur. Je sèche un peu (d'autant plus que j'utilise derrière cela
des signaux à temps réel).

Cordialement,

JKB



il faut boucler sur le read tant que E_ERRNO est égal à E_INTERRUPTED.
Il n'y a malheureusement pas moyen de le faire de façon atomique mais
ça, ça n'a jamais été un secret (il n'est nullement garanti qu'après un
write de x bytes dans un pipe, on puisse lire x bytes d'un seul coup de
l'autre coté.
Un solution pourait de faire du complete_read() (le read avec la boucle)
une fonction critique et de desactiver les signaux en entrant pour les
réactiver en sortant, auquel cas en cas de signal le signal sera catché
après le read.

Avatar
JKB
Le 22-01-2008, à propos de
Re: read() et signaux,
Aris écrivait dans fr.comp.lang.c :
En d'autres termes, j'aimerais qu'une ligne comme :

read(pipe, buffer, longueur)s

ne renvoie que 0, -1 ou longueur à l'exclusion de toute autre
valeur. Je sèche un peu (d'autant plus que j'utilise derrière cela
des signaux à temps réel).

Cordialement,

JKB



il faut boucler sur le read tant que E_ERRNO est égal à E_INTERRUPTED.
Il n'y a malheureusement pas moyen de le faire de façon atomique mais
ça, ça n'a jamais été un secret (il n'est nullement garanti qu'après un
write de x bytes dans un pipe, on puisse lire x bytes d'un seul coup de
l'autre coté.


Ça, je veux bien.

Un solution pourait de faire du complete_read() (le read avec la boucle)
une fonction critique et de desactiver les signaux en entrant pour les
réactiver en sortant, auquel cas en cas de signal le signal sera catché
après le read.


Le problème, c'est que d'après la page man, on peut récupérer deux
fonctionnements :

POSIX permet à un read() interrompu par un signal de renvoyer soit
le nombre doctets lus à ce point, soit -1, et de placer errno à EINTR.

J'ai l'impression que le même problème existe avec write()...

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.


Avatar
espie
In article ,
JKB wrote:
Bonjour à tous,

Je viens de trouver un bug sournois dans un de mes programmes écrit
en C et en lisant la page man de read() [Solaris], je m'aperçois
avec horreur que lorsque je lis dans un pipe, la fonction read()
peut être interrompue et que le read() peut s'arrêter avant d'avoir
lu le nombre de caractères demandés.

Problème : je synchronise plusieurs processus à l'aide de pipes et
de signaux. Comment s'arranger pour que les appels read() ne soient
pas interrompus par des signaux, donc que le contenu de mon buffer
soit celui attendu ?

En d'autres termes, j'aimerais qu'une ligne comme :

read(pipe, buffer, longueur)s

ne renvoie que 0, -1 ou longueur à l'exclusion de toute autre
valeur. Je sèche un peu (d'autant plus que j'utilise derrière cela
des signaux à temps réel).



Par essence, tu ne pourras pas. Mais tu as des garanties largement suffisantes
pour le fonctionnement de programmes correctement ecrits.

Tu as une constante (PIPE_BUF) qui vaut au moins 512, avec comme garantie
que toute ecriture dans un pipe de longueur <= PIPE_BUF se fera de maniere
atomique. Par exemple, si tu as plusieurs ecrivains, leurs messages ne seront
pas coupes en petit morceau.

Pour tes appels read, l'utilisation de sigaction() pour eviter d'etre
interrompu est une solution. Gerer EINTR en est une autre. sigprocmask()
pour proteger une section critique est la 3e.

Si on veut faire quelque chose de propre, il faut de toutes facons supposer
que tu auras a faire plusieurs read() jusqu'a obtenir un message complet.

Je ne peux pas te donner plus d'info sans en savoir plus sur l'architecture
de ton programme...

Avatar
JKB
Le 22-01-2008, à propos de
Re: read() et signaux,
Marc Espie écrivait dans fr.comp.lang.c :
In article ,
JKB wrote:
Bonjour à tous,

Je viens de trouver un bug sournois dans un de mes programmes écrit
en C et en lisant la page man de read() [Solaris], je m'aperçois
avec horreur que lorsque je lis dans un pipe, la fonction read()
peut être interrompue et que le read() peut s'arrêter avant d'avoir
lu le nombre de caractères demandés.

Problème : je synchronise plusieurs processus à l'aide de pipes et
de signaux. Comment s'arranger pour que les appels read() ne soient
pas interrompus par des signaux, donc que le contenu de mon buffer
soit celui attendu ?

En d'autres termes, j'aimerais qu'une ligne comme :

read(pipe, buffer, longueur)s

ne renvoie que 0, -1 ou longueur à l'exclusion de toute autre
valeur. Je sèche un peu (d'autant plus que j'utilise derrière cela
des signaux à temps réel).



Par essence, tu ne pourras pas. Mais tu as des garanties largement suffisantes
pour le fonctionnement de programmes correctement ecrits.

Tu as une constante (PIPE_BUF) qui vaut au moins 512, avec comme garantie
que toute ecriture dans un pipe de longueur <= PIPE_BUF se fera de maniere
atomique. Par exemple, si tu as plusieurs ecrivains, leurs messages ne seront
pas coupes en petit morceau.


Tiens, je ne connaissais pas. Je vais creuser le truc pour envoyer
de façon fiable mes informations par groupes d'au plus PIPE_BUF
octets. L'essentiel pour moi est d'avoir une transmission fiable.
Qu'elle soit interrompue ou non ne change rien à l'affaire pourvu
que tout arrive.

Pour tes appels read, l'utilisation de sigaction() pour eviter d'etre
interrompu est une solution. Gerer EINTR en est une autre. sigprocmask()
pour proteger une section critique est la 3e.

Si on veut faire quelque chose de propre, il faut de toutes facons supposer
que tu auras a faire plusieurs read() jusqu'a obtenir un message complet.

Je ne peux pas te donner plus d'info sans en savoir plus sur l'architecture
de ton programme...


Je n'ai pas trop envie d'entrer dans les détails, parce que le
programme est comment dire ? long !...

Merci,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.