[gull] bytes en transit dans un FIFO

Daniel Cordey dc at mjt.ch
Tue Nov 10 17:34:18 CET 2009


On Tuesday 10 November 2009 10:57:00 Philippe Strauss wrote:
> L'autre idée discutée hier soir avec des amis c'est SysV IPC, un ségment
> de mémoire partagée.

OK,

Je pense comprendre ton probleme...

Les "pipes" du kernel (le probleme avec les sockets est encore plus complexe) 
sont des buffers temporaires. Par defaut leur taille est de 8K. A priori, si 
tout va bien, un write() dans un pipe va engendrer un "signal" (kernel 
internal) pour l'autre process en attente de lecture. Donc, les donnees ne 
devraient etre dans le buffer que pendant un laps de temps tres court. Ce laps 
de temps peut aller de quelques dizaines de nanosecondes a... quelques 
dizaines de microsecondes (en moyenne). Mais, cette valeur ne peut pas etre 
determinee car elle depend d'un tres grand nonbres de parametres independants 
du processus. Tout au plus peut-on estime une valeur statistique moyenne avec 
une variance, mais sans plus... N'oublions pas, nosu ne sommes pas dans un 
environement de kernel temps-reel !

Ceci dit, pourquoi les fonctions habituelles (fstat etc.) ne peuvent elles pas 
me donner la quantite de bytes contenus dans le buffer ? Simplement 
parcequ'entre le moment ou l'on a ecrit ces donnees et le moment ou l'on 
effectue un fstat, il y a des chances que ces donnees ne soient plus la... 
N'oublions pas, 2 context-swicth dans ce cas...

C'est le process-scheduler du kernel qui decide quel(s) process doit(vent) 
extre execute losr d'un context switch. Les algorithmes dans ce domaine 
subissent des modifications continuelles et on ne peut se baser sur les regles 
en vigueurs car ces regles evoluent continuellement d'une version du kernel a 
l'autre.

On ne peut donc pas compter sur les "pipes" comme outil de gestion de flux, car 
il est impossible de determiner la situation exacte a un instant t. Il est 
donc necessaire de developer une solution ad-hoc pour ton probleme.

On doit developer un module "buffer" avec des methodes specifiques. Ces methodes 
seront chargees d'assurer une synchronisation temporelle entre l'entree et la 
sortie. Ce buffer doit pouvoir etre acceder par N flux en entree et (je pense) 
un flux en sortie. La synchronisation entre ecriture et lecture doit etre 
assuree par des semaphores, afin de "bloquer" l'acces pendant des operations de 
modifiaction des meta-donnees de chaque bloc de bytes. Sans doute le meilleur 
moyen d'assurer cette echange peut etre effectue a l'aide de "memory maped 
files" (see mmap()). Pourquoi des mmap plutot que des "Shared memory" (shm) ? 
Simplement parceque la gestion des phases de transitions 
(creation/destruction) est plus facile a gerer avec des mmap qu'avec des shm. 
De plus, les mmap etant relies au "file-system", il est plus facile de gerer 
les "locks" de regions et le contenu lorsque le process "createur" a disparu. 
Avec des shm, il faut aussi se taper la gestion des semaphores (sem), qui 
posent eux-aussi leurs problemes, J'ai pas mal bosser sur des partages de shm 
entre plusieurs process et la gestion de la phase de creation est complexe. Si 
l'on rajoute a cela qu'en meme temps il faut creer les semaphores (semop()) en 
s'assurant qu'aucun autre process ne fait la memem chose... c'est un peu 
touchy :-) Avec des mmap, c'est beaucoup plus simpel car on peut utiliser les 
fonctions de lock du file-systeme pour proteger les zones de modifiaction des 
meta-donnees. Autre avantage, lors de la disparition d'un process, les lock 
que celui-ci aurait effectue seront "nettoyes" par la gestion du file-system. 
Dans le cas des shm/sem, les semaphores restent dans un etat determine et on 
arrive facilement a des situation de blocage et le "nettoyage" s'avere souvent 
complexe.

Donc, tu implementes une librairie de lecture/ecriture de paquest de donnees 
dans un mmap() en mode FIFO... Tu peux t'octroyer des buffers de grande taille 
que tu peux gerer librement. La gestion du  "timimg" se fait alors a un plus 
haut niveau... soit al'ecriture qui decide d'ecraser un bloc qui ne devrait 
plus etre la, soit a la lecture en decidant d'ignorer le bloc le plus 
ancien... cela depend de la strategie que l'on veut mettre en place. L'autre 
avantage est la possibilite de faire de tres gros buffer permettant 
d'introduire la notion de "delay" ou de multi-serveurs... Les donnees, une 
fois ecrites par la partie "flux-entrant" vont finir par etre ecrites sur le 
disque (de maniere transparente) et le(s) process de lecture lira ses donnees 
du disque (aussi de maniere transparente). Bref, tous les avantages.

N'oublions pas non-plus que les mmap() utilisent (au niveau kernel) la meme 
architecture/technique que les segments de shared-memory. Experience faite, la 
gestion des semaphores peut s'averer tres complexes dans les phases 
transitoires et on obtiens les memes performances avec des mmap() sans en 
avoir les inconvenients. En effet, si les buffers ne sont pas trop gros, il y a 
toutes les chances que les donnees ne restent qu'en memoire et n'aillent 
jamais se promener sur le disque. Mais, meme la, les vitesses de lecture des 
disques permettent largement de faire de l'audio et/ou de la video. 

dc


More information about the gull mailing list